Python中有一个神奇的东西叫做生成器。
什么是生成器?
——形式地看,python语言中一旦关键字 yield出现,就表示一个生成器诞生了。
为了减少我们对生成器的恐惧和陌生感,让我们看一个简单的例子:
def fib():
a, b = 0, 1
while 1:
yield b
a, b = b, a+b
这段代码在做什么?作为一个对python有一定了解的同学,他几乎一眼就能看出来,这可能是一个生成斐波那契数序列的代码(yield的出现,可能会带来一点困惑)
这段代码中,fib在python解释器的存在形式是 generator 生成器。
且看
>> dir(fib())
>> print (type(fib()))
分别输出:
['class', 'delattr', 'doc', 'format', 'getattribute', 'hash', 'init', 'iter', 'name', 'new', 'reduce', 'reduce_ex', 'repr', 'setattr', 'sizeof', 'str', 'subclasshook', 'close', 'gi_code', 'gi_frame', 'gi_running', 'next', 'send', 'throw']
以及
<type 'generator'>
在dir(fib())中 我们可以看到fib实现了iter协议,说明它是一个可迭代的对象。可以像放到这样的句法当中:
for item in fib():
pass
生成器是重载了iter方法的可迭代对象
任何函数带 yield都会自动转换成生成器
例子:
def foo_func():
print "> May not be printed this line" (1)
exit()
yield "> This is generator"
foo_func()
调用 foo_func() 会发现 第(1)行不会打印
这是因为
关键字 yield 一旦出现在函数内部 函数就会自动转为一个生成器,生成器只有使用next方法才会被调用
如上
x = foo_func()
print(next(x))
生成器内置迭代器,请看:
dir(x) #x是一个生成器
[
'__class__', '__del__', '__delattr__', '__dir__',
'__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
'__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__',
'__le__', '__lt__', '__name__', '__ne__', '__new__',
'__next__', '__qualname__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__',
'__sizeof__', '__str__', '__subclasshook__',
'close', 'gi_code', 'gi_frame', 'gi_running',
'gi_yieldfrom', 'send', 'throw'
]
生成器对象实现了 iter 协议,因此它是可迭代对象,可以使用for Loop迭代
例子:
def one_to_ten():
val = 1
while val <= 10:
#print val
yield val
val += 1
for ele in one_to_ten():
print ele
生成器 是一种特殊的迭代器
一旦一个函数中包含了关键字 yield 那么它就会自动转化为一个生成器
生成器有异于一般函数的使用方式
神奇的yield
当一个生成器函数的 yield 被调用的时候,函数的内部状态就被“冻结”起来,函数内部的变量和值被保存起来。
下一行的代码直到next()方法调用才会再次被执行
next执行的时候,生成器在它上次被中断的地方恢复所有状态,并继续执行,直到下一个yield出现
def is_prime(number):
if number == 2:
return True
i = 2
while i * i <= number:
if number % i == 0:
return False
i += 1
else:
return True
def get_prime(number):
while True:
if is_prime(number):
yield number
number += 1
for element in get_prime(2):
print(element)
记住这些:
- generators 用来生成一系列的值
- yield 在生成器中的作用类似于 return;区别在于,yield保存了函数的局部状态,但return在函数中,会转移控制权,导致整个函数内部丢失所有状态
- 生成器是一种特殊的迭代器(即它实现了内部协议 iter)因此像迭代器一样,生成器可以用next()得到下一个值
PEP 255 - 简单生成器
在 Python 中加入生成器和 yield 语句的提议。
PEP 342 - 通过增强型生成器实现协程</dt>
增强生成器 API 和语法的提议,使其可以被用作简单的协程。
PEP 380 - 委托给子生成器的语法
引入 yield_from 语法以方便地委托给子生成器的提议。
PEP 525 - 异步生成器</dt>
通过给协程函数加入生成器功能对 PEP 492 进行扩展的提议。
</dd>