Python 的输出关键字是做什么的 ?
答复大纲/摘要
函数, 调用时, 返回生成器。 发电机是循环器, 因为它们执行循环程序, 以便您可以对它进行循环。 也可以发送一个发电机信息, 使其在概念上成为共同的常规。 在 Python 3 中, 您可以将一个发电机从一个发电机到另一个发电机, 从两个方向调用。 (附录: 包括顶部的答案在内的几个答案, 并讨论在发电机中使用返回的方法 。)
发电机:
收益率只是功能定义中的法律内涵,而将收益率列入功能定义使其返回产生者。
发电机的想法来自其他语言(见脚注1),其实施方式各有不同。 在Python的发电机中,代码的执行在生产点被冻结。当发电机被调用(方法在下文讨论)时,再恢复执行,然后冻结在下一个生产点。
输出提供了执行循环协议的简单方法,由以下两种方法定义:__iter__和__ext_。这两种方法都使对象成为可与收藏模块的Exerator摘要基础类进行打印的复制器。
def func():
yield 'I am'
yield 'a generator!'
让我们进行一些反省:
>>> type(func) # A function with yield is still a function
<type 'function'>
>>> gen = func()
>>> type(gen) # but it returns a generator
<type 'generator'>
>>> hasattr(gen, '__iter__') # that's an iterable
True
>>> hasattr(gen, '__next__') # and with .__next__
True # implements the iterator protocol.
生成器类型是一个子迭代器类型 :
from types import GeneratorType
from collections.abc import Iterator
>>> issubclass(GeneratorType, Iterator)
True
如有必要,我们可以这样打字检查:
>>> isinstance(gen, GeneratorType)
True
>>> isinstance(gen, Iterator)
True
迭代器的一个特征是,一旦耗竭,您无法再利用或重置它:
>>> list(gen)
['I am', 'a generator!']
>>> list(gen)
[]
如果你想再次使用其功能,你必须再做一次(见脚注2):
>>> list(func())
['I am', 'a generator!']
可以按方案生成数据,例如:
def func(an_iterable):
for item in an_iterable:
yield item
上述简单生成器也相当于以下生成器 -- -- 由于Python 3.3, 您可以使用以下来源的产量:
def func(an_iterable):
yield from an_iterable
但是,也允许向次级发电机授权,这一点将在下一节 " 与次级水泥合作授权 " 中加以解释。
计票:
窗体中显示一个表达式,该表达式允许将数据发送到生成器(见脚注3)
以下是一个例子,请注意收到的变量,该变量将指向发送到生成方的数据:
def bank_account(deposited, interest_rate):
while True:
calculated_interest = interest_rate * deposited
received = yield calculated_interest
if received:
deposited += received
>>> my_account = bank_account(1000, .05)
首先, 我们必须排队, 下一个是内建函数 。 它会调用合适的下一个或 下一步方法, 取决于您使用的 Python 版本 :
>>> first_year_interest = next(my_account)
>>> first_year_interest
50.0
现在我们可以将数据发送到生成器。 (“终结者”和“下一个”是一样的 ) :
>>> next_year_interest = my_account.send(first_year_interest + 1000)
>>> next_year_interest
102.5
合作社代表团到分科诊所分科
现在,请记住,Python 3的产量是可以得到的。 这使得我们可以将共同路线 委托给一个子烹饪:
def money_manager(expected_rate):
# must receive deposited value from .send():
under_management = yield # yield None to start.
while True:
try:
additional_investment = yield expected_rate * under_management
if additional_investment:
under_management += additional_investment
except GeneratorExit:
'''TODO: write function to send unclaimed funds to state'''
raise
finally:
'''TODO: write function to mail tax info to client'''
def investment_account(deposited, manager):
'''very simple model of an investment account that delegates to a manager'''
# must queue up manager:
next(manager) # <- same as manager.send(None)
# This is where we send the initial deposit to the manager:
manager.send(deposited)
try:
yield from manager
except GeneratorExit:
return manager.close() # delegate?
现在我们可以将功能委托给一个子生成器 并且它可以被一个发电机使用 就像上面那样:
my_manager = money_manager(.06)
my_account = investment_account(1000, my_manager)
first_year_return = next(my_account) # -> 60.0
现在模拟在账户中再增加1000, 加上账户的回报( 60.0 ) :
next_year_return = my_account.send(first_year_return + 1000)
next_year_return # 123.6
从PEP 380中,您可以阅读更多关于产量的确切语义。
其他方法:关闭和投掷
关闭方法在功能执行被冻结时提升发电机输出。 也可以被 __ del__ 调用, 这样您就可以设置任何清理代码, 用于处理发电机输出 :
my_account.close()
您也可以丢弃一个例外,该例外可在生成器中处理,或向用户传播:
import sys
try:
raise ValueError
except:
my_manager.throw(*sys.exc_info())
提高:
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
File "<stdin>", line 6, in money_manager
File "<stdin>", line 2, in <module>
ValueError
结论 结论 结论 结论 结论
我认为,我已处理了下列问题的所有方面:
Python 的输出关键字是做什么的 ?
事实证明,产量是很大的。我相信我可以为此再增加更详尽的例子。如果你需要更多的或有建设性的批评,请在下面评论,让我知道。
附录:
顶级/接受的答复的优先程度**
使用列表作为示例。 参见我上面的引用, 但概括地说: 循环含有 ` irit_ 的方法返回一个迭代器。 一个迭代器另外提供了一种 . next_ 的方法, 以循环为暗号, 以循环为代号, 直到它升起 停止 试运行, 一旦它确实升起 停止 试运行, 它会继续这样做 。 然后它会使用一个发电机表达方式来描述一个发电机。 由于一个发电机表达方式只是创建一个代用器的方便方式, 它只会混淆物质, 而我们还没有到达产值部分 。 在控制发电机耗竭时, 他调用 . next 方法( 只在 Python 2 中有效 ) , 而不是使用 内建函数, 下一步。 调用下一个 (obj) 将是一个适当的间接层, 因为他的代码在 Python 3. Itertools 中不起作用 。 这与结果完全无关 。 没有讨论 与 Python 3 中产生新功能收益的方法提供的方法和 Python 。
上方/接受的回答是一个非常不完整的回答。
回答的精度表示在发电机的表达或理解中产生产量。
语法目前允许列表理解中的任何表达式 。
expr_stmt: testlist_star_expr (annassign | augassign (yield_expr|testlist) |
('=' (yield_expr|testlist_star_expr))*)
...
yield_expr: 'yield' [yield_arg]
yield_arg: 'from' test | testlist
由于产量是一种表达方式,有些人认为在理解或生成方表达方式中使用产量是令人感兴趣的,尽管没有提出特别好的使用方式。
CPython核心开发商正在讨论其备抵的折旧问题。
2017年1月30日19:05时,布雷特坎农写道:在太阳上,2017年1月29日,16:39克雷格·罗德里格斯写道:我同意这两种方法。把事情保留在Python 3的状态是不对的,IMHO。我的投票是语法错误,因为你没有得到你期望的语法。我同意这对我们来说是一个明智的结局,因为任何依赖当前行为的代码都非常聪明,无法维持。在到达那里时,我们可能想要:在2.7的Py3k警告中,用3.7的Py3k警告来表示警告或破坏警告。x语法错误,Nick。 -- Nick Coghlan ncoghlan at gmail.com {Brisbane,澳大利亚,Gmail. com {Brisbane。
此外,还有一个未决问题(10544)似乎指向从来就不是一个好主意(PyPy, PyPy, 写在Python的Python执行文件,
底线,直到CPython的开发者告诉我们别的情况: 不要在生成器表达或理解中放出产量。
发电机中的回程声明
在Python 3 中:
在发电机函数中, 返回语句表示发电机已完成, 并将导致 StopLiveration 上升。 返回的值( 如果有的话) 用作构建 StopLiveration 的参数, 并成为 StopIturation. value 属性 。
Python 2 中的历史注释 : “ 在生成器函数中, 返回语句不允许包含表达式_ 列表 。 在此情况下, 光返回表示生成器已经完成, 并将导致停止使用 。 ” 表达式列表基本上是用逗号分隔的任何多个表达式 - 基本上在 Python 2 中, 您可以返回停止生成器, 但无法返回一个值 。
脚注脚注
将生成器的概念引入 Python 的建议中引用了语言 CLU、 Sather 和 图标 。 一般的想法是, 函数可以维持内部状态, 并产生用户需要的中间数据点 。 这承诺在性能上优于其他方法, 包括Python 线性线性, 某些系统中甚至没有这种系统。 这意味着, 范围天体虽然是可循环的, 但却不是迭代器, 因为它们是可以再利用的 。 和列表一样, 它们的 ` eter_ 方法返回替换器对象 。 收益最初是作为声明引入的, 意思是它只能在代码块的线性起始处出现 。 现在, 收益产生一种收益表达方式 。 https://docs. python.org/2/reference/spoint_stmts.html# grammar- token- yeld_stmt 。 提出这一修改是为了让用户将数据发送到生成器中。 。 要发送数据, 发送数据时, 就必须将它指定它为某种东西, 。