什么是生成器
可以理解为一种数据类型,这种数据类型自动实现了迭代器协议,其他的数据类型需要调用自己的内置的 _ _iter _ _()方法,所以生成器就是可迭代对象。next(generator)会从函数的当前位置向后执行到只有碰到的第一个yield语句,会弹出值,并暂停函数执行。
生辰器分类以及在python中的表现形式,
- 生成器函数:常规函数定义,但是,使用yield语句而不是return返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次从它离开的地方继续执行
- 生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表
生成器优势
1 . 生成器的好处是延迟计算,一次返回一个结果,也就是说,它不会一次生成所有的结果,这对于大数据处理,非常有用
2 . 生成器有效提高代码可读性
def test(): #生成器函数
yield 1
yield 2
yield 3
g = test()
print(g)
print(g.__next__())
他推导列表的中括号编程小括号,就是生成器
laomuji = ("鸡蛋 %s" % i for i in range(10)) #生成器表达式
print(laomuji)
print(laomuji.__next__())
print(laomuji.__next__())
print(next(laomuji))
#结果
<generator object <genexpr> at 0x00000000021F4F48>
鸡蛋 0
鸡蛋 1
鸡蛋 2
卖包子的例子
生成器优势:不占内存,效率高
def product_baozi():
for i in range(10):
print("正在生产包子")
yield "包子 %s" % i
print("正在卖包子")
pro_g = product_baozi()
baozi1 = pro_g.__next__()
print("来了一个人吃包子",baozi1)
time.sleep(3)
baozi2 = pro_g.__next__() #在一个人对象执行基础上,往下执行,所以该生成器通过__next__()函数一直往下取
#这个不占用内存,不用一下把所有包子都生成出来,有人买就生成一个包子,有第二个顾客来,就再生成第二个包子
print("来了一个人吃包子",baozi2)
#输出结果
正在生产包子
来了一个人吃包子 包子 0
正在卖包子
正在生产包子
来了一个人吃包子 包子 1
注意:print(next(i),“end”),粗略理解,在生成器next找不到下一次yield的时候,会输出end。这就是缺省值,以防抛出异常。
注意:
1 . 在生成器函数中,使用多个yield语句,执行一次后会暂停执行,把yield表达式的值返回。
2 . 再次执行会执行到下一个yield语句
3 . return语句依然可以终止函数运行,但return语句的返回值不能被获取到
4 . return会导致无法继续获取下一个值,抛出StopIteration异常。
5 . 如果函数没有显示的return语句,如果生成器函数执行到结尾,一样会抛出StopIteration异常,为了避免此异常,可用缺省值标记。