大佬教程收集整理的这篇文章主要介绍了实际上,Python 3.3中新的“ yield from”语法的主要用途是什么?,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
让我们先解决一件事。yIEld from g
等同的解释for v in g: yIEld v
yIEld
from
所有内容 处理。因为,让我们面对现实,如果yIEld
from
要做的就是扩大for
循环,那么它就不必保证会增加yIEld from
语言并阻止在Python 2.x中实现一堆新功能。
什么yIEld from
所做的就是 :
从某种意义上说,该连接是“透明的”,它也将正确传播所有内容,而不仅仅是生成的元素(例如,传播异常)。
该连接是在意义上是“双向”的数据可以同时寄给 从 和 到 一个发电机。
( 如果我们在谈论TCP,yIEld from g
可能意味着“现在暂时断开客户端的套接字,然后将其重新连接到该其他服务器套接字”。)
顺便说一句,如果您不确定 向生成器发送数据 意味着什么,则需要删除所有内容并首先阅读 协程 ,它们非常有用(将它们与 子例程进行 对比),但不幸的是在Python中鲜为人知。戴夫·比兹利(Dave Beazley)的《协程》好奇课程是一个很好的开始。阅读幻灯片24-33以获得快速入门。
def reader():
"""A generator that fakes a read from a file, socket, etc."""
for i in range(4):
yIEld '<< %s' % i
def reader_wrapper(g):
# Manually iterate over data produced by reader
for v in g:
yIEld v
wrap = reader_wrapper(reader())
for i in wrap:
print(i)
# Result
<< 0
<< 1
<< 2
<< 3
无需手动迭代reader()
,我们可以yIEld from
做到。
def reader_wrapper(g):
yIEld from g
那行得通,我们消除了一行代码。意图可能会更清晰(或不太清楚)。但是生活没有改变。
现在,让我们做一些更有趣的事情。让我们创建一个名为协程的程序writer
,它接受发送给它的数据并写入套接字,fd等。
def writer():
"""A coroutIne that writes data *sent* to it to fd, socket, etc."""
while True:
w = (yIEld)
print('>> ', w)
现在的问题是,包装器函数应如何处理将数据发送到编写器,以便将发送到包装器的任何数据 透明地 发送到writer()
?
def writer_wrapper(coro):
# TBD
pass
w = writer()
wrap = writer_wrapper(w)
wrap.send(NonE) # "prime" the coroutIne
for i in range(4):
wrap.send(i)
# Expected result
>> 0
>> 1
>> 2
>> 3
包装器需要(显然) 接受 发送给它的数据,并且还应处理stopiteration
for循环耗尽时的。显然只是做for x in coro:
yIEld x
不会做。这是一个有效的版本。
def writer_wrapper(coro):
coro.send(NonE) # prime the coro
while True:
try:
x = (yIEld) # Capture the value that's sent
coro.send(X) # and pass it to the writer
except stopiteration:
pass
或者,我们可以这样做。
def writer_wrapper(coro):
yIEld from coro
这样可以节省6行代码,使其更具可读性,并且可以正常工作。魔法!
让我们变得更加复杂。如果我们的作者需要处理异常怎么办?假设writer
句柄a遇到一个SpamException
,它将打印***
。
class SpamException(Exception):
pass
def writer():
while True:
try:
w = (yIEld)
except SpamException:
print('***')
else:
print('>> ', w)
如果我们不改变writer_wrapper
怎么办?它行得通吗?我们试试吧
# writer_wrapper same as above
w = writer()
wrap = writer_wrapper(w)
wrap.send(NonE) # "prime" the coroutIne
for i in [0, 1, 2, 'spam', 4]:
if i == 'spam':
wrap.throw(SpamException)
else:
wrap.send(i)
# Expected Result
>> 0
>> 1
>> 2
***
>> 4
# Actual Result
>> 0
>> 1
>> 2
TraceBACk (most recent call last):
... redacted ...
file ... in writer_wrapper
x = (yIEld)
__main__.SpamException
嗯,它不起作用,因为x = (yIEld)
只是引发了异常,一切都崩溃了。让它正常工作,但手动处理异常并将其发送或将其抛出到子生成器(writer
)中
def writer_wrapper(coro):
"""Works. Manually catches exceptions and throws them"""
coro.send(NonE) # prime the coro
while True:
try:
try:
x = (yIEld)
except Exception as e: # This catches the SpamException
coro.throw(E)
else:
coro.send(X)
except stopiteration:
pass
这有效。
# Result
>> 0
>> 1
>> 2
***
>> 4
但是,这也是!
def writer_wrapper(coro):
yIEld from coro
该yIEld from
透明地处理发送值或抛出的值到副发电机。
但是,这仍然不能涵盖所有极端情况。如果外部发电机关闭,会发生什么?如果子生成器返回一个值(是的,在Python
3.3+中,生成器可以返回值),该如何处理?这yield
from
透明地处理所有角落的情况下确实是令人印象深刻。yIEld from
只是神奇地工作并处理了所有这些情况。
我个人认为这yIEld from
是一个糟糕的关键字选择,因为它不会使 双向
性变得显而易见。还提出了其他关键字(例如,delegate
但被拒绝了,因为向该语言添加新关键字比合并现有关键字要困难得多。
总之,最好将其yIEld from
视为 调用方和子生成方之间的。
参考文献:
我很难把脑袋包在PEP 380上。
[更新]
现在,我了解了造成困难的原因。我曾经使用过生成器,但从未真正使用过协程(由PEP-342引入)。尽管有一些相似之处,但生成器和协程基本上是两个不同的概念。了解协程(不仅是生成器)是了解新语法的关键。
恕我直言, 协程是最晦涩的Python功能 ,大多数书籍使它看起来毫无用处且无趣。
感谢您做出的出色回答,特别感谢agf及其与David
Beazley演讲相关的评论。大卫·罗克。
以上是大佬教程为你收集整理的实际上,Python 3.3中新的“ yield from”语法的主要用途是什么?全部内容,希望文章能够帮你解决实际上,Python 3.3中新的“ yield from”语法的主要用途是什么?所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。