第一种情况——简单生成器
生成器表达式 与您描述的简单生成器(x*x for x in range(3))
函数大致相同。但是,genexp 的作用域可能会稍微复杂一些(这就是为什么我们通常建议您立即使用生成器表达式而不是传递它们)。
第二种情况——增强型生成器
带有 的代码是增强生成器y = yield x
的示例,用于将数据发送到正在运行的生成器中,本质上是在正在运行的生成器和调用代码之间创建双向通信通道。
发送/接收逻辑的主要用例是实现协程和生成器蹦床。请参阅 David Beazley 的这个蹦床示例。
增强的生成器是 Twisted Python实现协程的漂亮内联回调的关键。
如何检查生成器
对于变量y in y = func()
,唯一的检查技术是检查公共 API:
>>> y = func()
>>> dir(y)
['__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']
如何检查生成器功能
对于生成器函数本身,您可以使用dis模块检查代码以了解其工作原理:
>>> def func():
x = 1
while 1:
y = yield x
x += y
>>> import dis
>>> dis.dis(func)
3 0 LOAD_CONST 1 (1)
3 STORE_FAST 0 (x)
4 6 SETUP_LOOP 21 (to 30)
5 >> 9 LOAD_FAST 0 (x)
12 YIELD_VALUE
13 STORE_FAST 1 (y)
6 16 LOAD_FAST 0 (x)
19 LOAD_FAST 1 (y)
22 INPLACE_ADD
23 STORE_FAST 0 (x)
26 JUMP_ABSOLUTE 9
29 POP_BLOCK
>> 30 LOAD_CONST 0 (None)
33 RETURN_VALUE
使用调试器跟踪代码
您可以使用pdb调试器逐步跟踪代码。
>>> import pdb
>>> y = func()
>>> pdb.runcall(next, y)
> /Users/raymond/Documents/tmp.py(2)func()
-> x = 1
(Pdb) s
> /Users/raymond/Documents/tmp.py(3)func()
-> while 1:
(Pdb) s
> /Users/raymond/Documents/tmp.py(4)func()
-> y = yield x
(Pdb) p locals()
{'x': 1}
(Pdb) s
> /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/bdb.py(440)runcall()
-> self.quitting = 1
(Pdb) s
1
>>> pdb.runcall(y.send, 10)
> /Users/raymond/Documents/tmp.py(5)func()->1
-> x += y
(Pdb) s
> /Users/raymond/Documents/tmp.py(4)func()->1
-> y = yield x
(Pdb) locals()
{'__return__': 1, 'x': 11, 'y': 10}