我正在python 3中尝试使用生成器,并编写了这个相当人为的生成器:
def send_gen():
print(" send_gen(): will yield 1")
x = yield 1
print(" send_gen(): sent in '{}'".format(x))
# yield # causes StopIteration when left out
gen = send_gen()
print("yielded {}".format(gen.__next__()))
print("running gen.send()")
gen.send("a string")
输出:
send_gen(): will yield 1
yielded 1
running gen.send()
send_gen(): sent in 'a string'
Traceback (most recent call last):
File "gen_test.py", line 12, in <module>
gen.send("a string")
StopIteration
因此,
gen.__next__()
到达行x = yield 1
并产生1。我认为x
将被分配给None
,然后gen.send()
将查找下一个yield
语句,因为x = yield 1
被“使用”,然后获得了StopIteration
。取而代之的是,似乎发生了什么事:
x
被发送了“字符串”,并打印出来,然后python尝试寻找下一个yield
并获得StopIteration
。所以我试试这个:
def send_gen():
x = yield 1
print(" send_gen(): sent in '{}'".format(x))
gen = send_gen()
print("yielded : {}".format(gen.send(None)))
输出 :
yielded : 1
但是现在没有错误了。将
send()
分配给yield
之后,x
似乎没有尝试寻找下一个None
语句。为什么行为略有不同?这与我如何启动发电机有关吗?
最佳答案
行为没有什么不同。在第二种设置中,您从未超越生成器中的第一个yield
表达式。注意StopIteration
是而不是错误;这是正常的行为,只要发电机结束,就会发出预期的信号。在第二个示例中,您从未到达生成器的末尾。
每当生成器到达yield
表达式时,执行就在那里暂停,该表达式在恢复到生成器之前不会在生成器中产生任何东西。 gen.__next__()
或gen.send()
都将从该点恢复执行,yield
表达式将生成gen.send()
或None
传递的值。如果有帮助,您可以将gen.__next__()
视为gen.send(None)
。在这里要实现的一件事是gen.send()
使yield
首先返回发送值,然后再返回到下一个yield
。
因此,考虑到您的第一个示例生成器,将发生以下情况:gen = send_gen()
创建生成器对象。代码在函数的最上方暂停,不执行任何操作。 gen.__next__()
或gen.send(None)
;生成器启动并执行,直到第一个yield
表达式:print(" send_gen(): will yield 1")
yield 1
现在执行暂停。 gen.__next__()
或gen.send(None)
调用现在返回1
,即yield 1
产生的值。因为生成器现在已暂停,所以尚未进行x = ...
分配!只有在再次恢复生成器时才会发生这种情况。 gen.send("a string")
,在第二个示例中不进行任何调用。因此,对于第一个示例,现在恢复了generator函数:x = <return value of the yield expression> # 'a string' in this case
print(" send_gen(): sent in '{}'".format(x))
现在函数结束,因此StopIteration
升高了。
因为在第二个示例中从未恢复过生成器,所以未到达生成器的末尾,并且不会引发StopIteration
异常。
请注意,由于生成器从函数的顶部开始,所以此时没有yield
表达式返回您用gen.send()
发送的内容,因此第一个gen.send()
值必须始终为None
或引发异常。最好使用一个显式的gen.__next__()
(或一个next(gen)
函数调用)来“启动”生成器,以便在第一个yield
表达式处将其暂停。
关于python - Python : Behaviour of send() in generators,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36997078/