我有一个叫做x的函数,它会生成一个像这样的生成器:
a = 5
def x():
global a
if a == 3:
raise Exception("Stop")
a = a - 1
yield a
然后在python shell中,我像这样调用该函数:
>>> print x().next()
>>> 4
>>> print x().next()
>>> 3
>>> print x().next()
>>> <python-input-112-f3c02bba26c8> in x()
2 global a
3 if a == 3:
----> 4 raise Exception
5 a = a - 1
6 yield a
Exception:
但是,当我调用该函数并将其分配给变量时,其行为会有所不同:
>>> a = 5
>>> b = x()
>>> print b.next()
>>> 4
>>> print b.next()
>>> ----> 1 b.next()
StopIteration:
这怎么可能呢?它不应该打印出3并在下一次迭代中提高StopIteration吗?
PS:我知道,当我第一次调用该函数时,主体不会运行,只会生成一个generator。我不明白的是,如果我调用并将其分配给变量,会发生什么变化?
在第一个示例中,您每次都创建一个新的生成器:
x().next()
这从顶部开始生成器,因此是第一个语句。当a == 3
引发异常时,否则生成器仅屈服并暂停。
当您稍后分配生成器时,全局a
起始于5
,然后代码从其离开的位置继续直到它结束或遇到另一条yield
语句,然后结束。生成器函数结束时,将引发StopIteration
。
让我们将其分解为以下步骤:
a = 5
。您创建新的生成器并对其进行调用.next()
。执行以下代码:
global a
if a == 3: # False
raise Exception("Stop")
a = a - 1 # a is now 4
yield a
生成器在最后一行暂停,并4
屈服。
您创建一个新的生成器并对其进行调用.next()
。a
是4
在开始:
global a
if a == 3: # False
raise Exception("Stop")
a = a - 1 # a is now 3
yield a
生成器在最后一行暂停,并3
屈服。
您创建一个新的生成器并对其进行调用.next()
。a
是3
在开始:
global a
if a == 3: # True
raise Exception("Stop")
引发异常。
您a = 5
再次设定。
您创建一个新的生成器,在其中存储引用b
并对其进行调用.next()
。执行以下代码:
global a
if a == 3: # False
raise Exception("Stop")
a = a - 1 # a is now 4
yield a
生成器在最后一行暂停,并4
屈服。
您.next()
再次调用由引用的相同的现有生成器b
。该代码在暂停点处恢复。
该函数此时没有更多代码,然后返回。StopIteration
被提出。
如果要使用循环,则可以更好地看到不同之处:
>>> def looping(stop):
... for i in looping(stop):
... yield i
...
>>> looping(3).next()
0
>>> looping(3).next()
0
请注意,每次创建新生成器时,循环都是从头开始的。但是,存储参考,您会发现它继续存在:
>>> stored = looping(3)
>>> stored.next()
0
>>> stored.next()
1
>>> stored.next()
2
>>> stored.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
在循环期间,每次yield
执行表达式时,代码都会暂停;调用.next()
将从上次离开的位置继续执行该功能。
的StopIteration
例外是完全正常的; 生成器传达它们完成的方式。一个for
循环查找该异常来结束循环:
>>> for i in looping(3):
... print i
...
0
1
2
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句