何为使用yieldPython 中的关键字?

比如说,我在试着理解这个代码1:

def _get_child_candidates(self, distance, min_dist, max_dist):
    if self._leftchild and distance - max_dist < self._median:
        yield self._leftchild
    if self._rightchild and distance + max_dist >= self._median:
        yield self._rightchild  

这就是打电话的人:

result, candidates = [], [self]
while candidates:
    node = candidates.pop()
    distance = node._get_dist(obj)
    if distance <= max_dist and distance >= min_dist:
        result.extend(node._values)
    candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))
return result

当方法_get_child_candidates是否调用 ? 列表是否返回 ? 单元素 ? 是否又调用 ? 以后的呼叫何时停止 ?


1. 本代码由Jochen Schulz(jrschulz)编写,他为公制空间制作了一个伟大的Python图书馆。模块 m 空间.

当前回答

什么是yieldPython的关键字是用吗?

答复大纲/摘要

  • 函数函数函数函数yield当呼唤,返回返回 a发电机发电机.
  • 发电机是迭代器,因为它们实施动态自动交换协议这样你就可以绕过他们了
  • 发电机也可以已发送信息使它在概念上成为共礼管.
  • 在Python 3,你可以代表代表从一个发电机到另一个发电机,双向yield from.
  • (附录对几个答案,包括前一个答案,并讨论使用return在发电机中。 )

发电机:

yield只是在功能定义中的法律内涵,而且列入《公约》yield在函数定义中,函数定义使其返回生成器。

发电机的构想来自其他语文(见脚注1),其实施方式各有不同。冻结当发电机被调用(方法将在下文讨论)时,恢复执行,然后冻结在下一个产地。

yield简易的给养,执行循环协议由以下两种方法界定:__iter____next__。这两种方法都使对象成为可键入检查对象的迭代器。Iterator基础摘要类collections模块。

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

A. 单Iterator 即已用尽,您不能重新使用或重置它:

>>> 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来看,您可以使用yield from:

def func(an_iterable):
    yield from an_iterable

不过,yield from还允许向次级发电机授权,将在下一节 " 与子大麻合作的代表团 " 中加以解释。

计票:

yield窗体中的表达式,该表达式允许将数据发送到生成器(见脚注3)

举一个例子,请注意received变量,该变量将指向发送到生成方的数据:

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)

首先,我们必须排队 发电机与内建功能,nextnext__next__方法, 取决于您使用的 Python 版本 :

>>> first_year_interest = next(my_account)
>>> first_year_interest
50.0

现在我们可以把数据传送到发电机里了发送中发送None与调用相同next.) :

>>> next_year_interest = my_account.send(first_year_interest + 1000)
>>> next_year_interest
102.5

合作代表团yield from

现在,回顾yield fromPython 3 提供。 这让我们可以将 共同路线 委托给子coustine :


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

您可以阅读更多关于yield fromPEP380号

其他方法:关闭和投掷

缩略close方法生成GeneratorExit功能执行被冻结时, 这也会被调用 。__del__以便您可以设置任何清理代码, 用于处理GeneratorExit:

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

结论 结论 结论 结论 结论

我认为,我已处理了下列问题的所有方面:

什么是yieldPython的关键字是用吗?

事实证明yield我肯定我可以为此再增加更详尽的例子。如果你们想要更多或有建设性的批评,请在下面评论,让我知道。


附录:

顶级/接受的答复的优先程度**

  • 它被混淆了 是什么制造了易 易 易 性,仅以列表作为示例。见以上我的引用,但摘要:a易 易 易 性具有 a 的__iter__返回方法返回振动器。 A. A.振动器额外提供a.__next__方法,该方法隐含地称为:for循环直到它升起StopIteration,一旦它升起StopIteration它将继续这样做。
  • 然后,它用发电机表达式来描述发电机是什么。 因为发电机表达式只是创建一个振动器,它只是混淆了事情, 而我们仍然还没有达到yield部分。
  • 控制发电机耗竭他呼唤.next方法(仅在Python 2 中有效),当他应该使用内设函数时,next调用next(obj)这是一种适当的间接分解层,因为他的代码在Python 3号行不通。
  • 这跟什么无关yield完全没有。
  • 不讨论采用哪些方法yield与新功能一起提供yield fromPython 3 号的Python 3。

上方/接受的回答是一个非常不完整的回答。

答复的精度答复建议yield中显示或理解生成方的表达或理解。

语法目前允许列表理解中的任何表达式 。

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日17:39Craig Rodrigues写道:

我不管用哪一种方法都行,把事情和在Python 3的一样丢在一边是不好的,IMHO。

我的投票是 语法错误,因为你没有得到 你期望的语法。

我同意这对我们来说是个明智的地方 因为任何依靠当前行为的守则 都太聪明了 无法维持下去

就到达那里而言,我们很可能想要:

  • 3.7年的语法警告或折旧警告
  • 2.7.x.x.中的Py3k警告
  • 3.8 中的语法rror

干杯,尼克。

- Nick Coghlan ncoghlan at gmail.com Brisbane, 澳大利亚布里斯班

此外,还有未决问题(10544)这一点似乎指着着《公约》和《公约》从未是一个好主意(PyPy, PyPython 的 Python 执行书写在 Python 上, 已经在提高语法警告 。 )

直至CPython的开发商告诉我们:别放yield中显示或理解生成方的表达或理解。

缩略return生成器中的语句

Python 3:

在发电机功能中,return声明中表示发电机已经完成,并将导致StopIteration返回的值(如果有的话)用作构建的论据。StopIteration成为StopIteration.value属性。

历史记录,Python 2: "在发电机功能中,return不允许包含语句expression_list在这种背景下,光return表示发电机完成并导致StopIteration将升起。expression_list基本上是用逗号分隔的任意数表达式 - 基本上是在 Python 2 中, 您可以用return,但你不能返回一个值。

脚注脚注

  1. 在向Python引入发电机概念的提案中,提到了CLU、Sather和“图标”等语言。 通常的想法是,功能可以维持内部状态,并产生用户需要的中间数据点。 这保证了这一功能能够维持内部状态,并产生中间数据点。业绩优于其他方法,包括Python线在某些系统上甚至都找不到

  2. 这意味着,例如,range对象不是物体Iteratori 尽管它们是可循环的, 因为它们可以被再利用。就像列表一样,它们__iter__方法返回迭代对象。

  3. yield最初作为声明被引入,意思是它只能出现在代码块的线条开头。yield创建收益表达式 。https://docs.python.org/2/reference/simple_stmts.html#grammar-token-yield_stmt这一变化是:拟议拟议拟议数允许用户像收到数据一样将数据发送到生成器中。 要发送数据, 就必须能够将数据指定给某些东西, 因此, 声明是行不通的 。

其他回答

放弃是一个对象

A A Areturn在函数中返回单一值。

如果您愿意,如果需要函数返回一大批值,使用yield.

更重要的是yield是 a 是障碍屏障.

就像CUDA语言中的屏障, 它不会转移控制 直到它完成。

也就是说,它会运行您函数的代码 从开始直到启动yield。然后,它将返回循环的第一个值。

然后,其他每通电话都会运行您在函数中写下的循环, 返回下一个值, 直到没有任何值可以返回 。

这样想吧:

a. a. a. a. a. a. a. a. a. a. a. a. a. a. a. a. a. a. a. a. a. a. a. a. a. a. a. a. a. a. a. a. a. a. a. a. a. a.next()方法。因此,一个产出式的函数最终会变成这样:

原文:

def some_function():
    for i in xrange(4):
        yield i

for i in some_function():
    print i

Python 翻译用上述代码所做的基本上就是:

class it:
    def __init__(self):
        # Start at -1 so that we get 0 when we add 1 below.
        self.count = -1

    # The __iter__ method will be called once by the 'for' loop.
    # The rest of the magic happens on the object returned by this method.
    # In this case it is the object itself.
    def __iter__(self):
        return self

    # The next method will be called repeatedly by the 'for' loop
    # until it raises StopIteration.
    def next(self):
        self.count += 1
        if self.count < 4:
            return self.count
        else:
            # A StopIteration exception is raised
            # to signal that the iterator is done.
            # This is caught implicitly by the 'for' loop.
            raise StopIteration

def some_func():
    return it()

for i in some_func():
    print i

更深入了解幕后发生的事for循环可以重写到此 :

iterator = some_func()
try:
    while 1:
        print iterator.next()
except StopIteration:
    pass

这更有意义还是更让人困惑?

我应当指出,这一点a 为说明目的过于简化。 )

缩略yieldkeywit 用于查点/ 字符中, 函数预期将返回一个输出。 我想引用此非常简单 。例例A:

# example A
def getNumber():
    for r in range(1,10):
        return r

上述函数只返回1即使它被多次调用。 如果我们替换returnyield以内例B:

# example B
def getNumber():
    for r in range(1,10):
        yield r

它会回来的1第一次调用时2当日,3,4直至10岁为止的增量。

尽管《公约》例B在概念上是真实的,但称它为Python 3( 3)我们必须采取以下行动:


g = getNumber() #instance
print(next(g)) #will print 1
print(next(g)) #will print 2
print(next(g)) #will print 3

# so to assign it to a variables
v = getNumber()
v1 = next(v) #v1 will have 1
v2 = next(v) #v2 will have 2
v3 = next(v) #v3 will have 3

佩顿有什么差错?

Python 中的 Yield 关键字类似于用于返回 Python 中的值或对象的返回语句。 但是, 存在微小的差别。 收益语句返回一个生成符, 而不是简单地返回一个值, 而返回一个函数的生成符。

在程序内,当您调用一个函数,该函数有一个输出语句时,一旦遇到一个输出,函数的执行即停止,然后将生成器的一个对象返回到函数调用器。用更简单的文字,产出关键字将把一个与该关键字一起指定的表达式转换为生成器对象,然后返回到调用器。因此,如果您想要获得在生成器对象内存储的值,则需要将该关键字复制到该对象上。

它不会破坏本地变量的状态。 当调用函数时, 执行将从最后一个输出表达式开始。 请注意, 包含输出关键字的函数被称为生成函数 。

当您使用含有返回值的函数时,每次调用函数时,该函数从一组新的变量开始。反之,如果使用一个生成函数而不是正常函数,则执行将从它左最后的位置开始。

如果您想要从函数中返回多个值, 您可以使用输出关键字来使用生成函数。 输出表达式返回多个值。 它们返回一个值, 然后等待, 保存本地状态, 然后再恢复 。

资料来源:https://www.simplilearn.com/tutorials/python-tutorial/yield-in-python

许多人使用return而不是yield,但在某些情况下yield能够更有效和更方便地开展工作。

以下是一个例子:yield绝对是最好的:

返回返回(在职能)

import random

def return_dates():
    dates = [] # With 'return' you need to create a list then return it
    for i in range(5):
        date = random.choice(["1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th", "10th"])
        dates.append(date)
    return dates

收益率(在职能)

def yield_dates():
    for i in range(5):
        date = random.choice(["1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th", "10th"])
        yield date # 'yield' makes a generator automatically which works
                   # in a similar way. This is much more efficient.

呼叫功能

dates_list = return_dates()
print(dates_list)
for i in dates_list:
    print(i)

dates_generator = yield_dates()
print(dates_generator)
for i in dates_generator:
    print(i)

两种功能都做相同的事情,但yield使用三行而不是五行, 并有一个更少的变量需要担心 。

这是代码的结果:

Output

正如你可以看到两个函数都做相同的事情。唯一的区别是return_dates()给出列表并yield_dates()给发电机。

真实生活中的范例就是 逐行读取文件行 或者你只是想制造一个发电机