Python意外的StopIteration

时间:2014-08-03 07:55:42

标签: python generator next assign operator-precedence

这是我的代码

class A:
    pass

def f():
    yield A()

def g():
    it = f()
    next(it).a = next(it, None)

g()

产生由StopIteration引起的next(it).a = next(it, None)错误。为什么呢?

文档说如果提供了默认值,next函数不会引发StopIteration,我希望它能从生成器(A实例中获取第一个项目)并将a属性设置为None

2 个答案:

答案 0 :(得分:8)

由于f只生成一个值,因此您只能在其上调用next一次。

表达式的右侧(next(it, None))在左侧之前进行评估,从而耗尽发电机。

然后在左侧调用next(it).a会引发StopIteration

答案 1 :(得分:3)

您的f()生成器函数只会产生一个值。之后,它已用尽并提升StopIteration

>>> class A:
...     pass
... 
>>> def f():
...     yield A()
... 
>>> generator = f()
>>> generator
<generator object f at 0x10be771f8>
>>> next(generator)
<__main__.A object at 0x10be76f60>
>>> next(generator)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

那是因为f()中的无循环不止一次产生,生成器函数本身不会循环,只是因为你可以使用它 一个循环。

请注意,对于赋值,Python先执行右侧表达式 first ,然后再确定将分配给的内容。因此首先调用next(it, None),分配的next(it).a称为 second

f()函数的主体与任何其他Python函数一样执行,并添加暂停。生成器上的next()取消暂停代码,然后代码运行直到执行下一个yield语句。该声明然后再次暂停发电机。如果函数结束(返回),则会引发StopIteration

f()生成器中,这意味着:

  1. 当您致电f()时,会创建一个新的生成器对象。功能正文已暂停。
  2. 您第一次就此致电next()。代码开始运行,创建A()的实例并生成该实例。该功能再次暂停。
  3. 您第二次致电next()。代码开始运行,到达函数的末尾,然后返回。 StopIteration被提出。
  4. 如果您向f()添加循环,或只是添加第二个 yield行,则代码可以正常运行:

    def f():
        yield A()
        yield A()
    

    def f():
        while True:
            yield A()