python零基础学习2-函数2-生成器(generator)

列表生成式

print([i*2 for i in range(10)])    #[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

缺点: 一次生成元素较多的列表, 占用内存较大

解决方案: 在使用过程中依次生成

生成器

使用列表生成式创建生成器:

 

b=(i*2 for i in range(10))     #产生一个生成器, 但是并没有元素
print(b)       #<generator object <genexpr> at 0x0000006E78879308>

for i in b:
    print(i)                 #可正常打印

 

  • 生成器只能通过循环调用, 生成元素, 不能使用b[100], 切片等功能
  • b.__next__()   可以求下一个, 但无法回到上一个
  • 生成器只能记住当前元素, 之前的元素不保存

 

使用函数创建生成器:

示例: 斐波那契数列

使用函数实现

#使用函数实现
def fib(max):
    n,a,b=0,0,1
    while n<max:
        print(b)
        a,b=b,a+b     #这种赋值方式, 相当于先将b, a+b赋值给临时变量, 再同时赋给a,b
        n=n+1
    return "done"
fib(10)

使用生成器实现

#改造为生成器
def fib(max):
    n,a,b=0,0,1
    while n<max:
        yield b       #只要有yield就是生成器
        a,b=b,a+b
        n=n+1
    return "done"    #异常打印信息

fib_gen=fib(4)
#调用方法
# print(fib_gen.__next__())
# print(fib_gen.__next__())
# print(fib_gen.__next__())
# print(fib_gen.__next__())
# print(fib_gen.__next__())   #next超出范围时会抛出异常

#防止超出范围的调用方法
while True:
    try:
        x=fib_gen.__next__()
        print(x)
    except StopIteration as e:
        print(e.value)           #打印值为done
        break

 

实际应用: 可通过yield实现单线程下并发的功能

示例(异步I/O的雏形):

import time
def consumer(name):
    print(name,"开始消费~")

    while True:
        baozi=yield
        print(baozi,"",name,"吃了~")


def producer(name):
    c1=consumer("A")   #生成两个生成器
    c2=consumer("B")

    c1.__next__()      #第一次执行, 打印开始消费, 之后停在yield处, 不执行
    c2.__next__()

    for i in range(10):
        time.sleep(2)
        print(name,"做了两个包子")

        c1.send(i+1)   #给yield传值, 并执行baozi=yield, 继续执行
        c2.send(i+1)

producer("alex")

 

迭代器

  • 可直接作用于for循环的数据类型: 列表, 字段, 元组, 集合, 字符串, 生成器.  统称为可迭代对象(Iterable)
  • 可以被__next__()函数调用并不断返回下一个值的对象统称为迭代器(Iterator), 没数据时抛出StopIteration异常
  • 可使用isintance()判断

 

from  collections import Iterable
from collections import Iterator
print(isinstance([],Iterable))   #True
print(isinstance([],Iterator))    #False
print( isinstance((x for x in range(10)),Iterator))   #True

 

  • 生成器都是迭代器, 但list, dict, str虽然是可迭代对象, 但并不是迭代器
  • 可使用iter()将可迭代对象变为迭代器
a=[1, 2, 3]
b=iter(a)
print(b.__next__())
print(b.__next__())
print(b.__next__())

 

 

迭代器特征:

  • 表示一个数据流, 不能提前知道序列长度
  • 计算是惰性的
  • 甚至可以表示无限大的数据流, 例如全体自然数

range(0,10)也是迭代器

 

posted on 2017-10-19 16:34  bell03  阅读(137)  评论(0)    收藏  举报

导航