Python意外的StopIteration

vau*_*tah 0 python generator operator-precedence next assign

这是我的代码

class A:
    pass

def f():
    yield A()

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

g()
Run Code Online (Sandbox Code Playgroud)

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

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

sap*_*api 8

因为f只产生一个值,所以你只能调用next一次.

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

然后呼叫next(it).a左侧将加注StopIteration.


Mar*_*ers 5

您的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
Run Code Online (Sandbox Code Playgroud)

这是因为没有循环可以f()产生多次,生成器函数本身不会循环,只是因为您可以循环中使用它。

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

函数体的f()执行方式与任何其他 Python 函数一样,只是添加了暂停next()在生成器上取消暂停代码,然后代码运行直到yield执行下一条语句。然后该语句再次暂停生成器。如果函数结束(返回),StopIteration则引发。

在你的f()生成器中这意味着:

  1. 当你调用f()一个新的生成器对象时被创建。函数体暂停。
  2. next()第一次调用它。代码开始运行,创建一个实例A()并生成该实例。该功能再次暂停。
  3. next()第二次调用它。代码开始运行,到达函数末尾,然后返回。StopIteration被提出。

如果您添加一个循环f(),或者只是添加第二 yield行,您的代码就可以工作:

def f():
    yield A()
    yield A()
Run Code Online (Sandbox Code Playgroud)

或者

def f():
    while True:
        yield A()
Run Code Online (Sandbox Code Playgroud)