何为使用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 空间.

当前回答

TL; DR TR; TL; TDR

代替此:

def square_list(n):
    the_list = []                         # Replace
    for x in range(n):
        y = x * x
        the_list.append(y)                # these
    return the_list                       # lines

这样做:

def square_yield(n):
    for x in range(n):
        y = x * x
        yield y                           # with this one.

每当你发现自己从头到尾 编造了一张清单yield换成每块

这是我第一次"啊哈"节奏节奏


yield是 a 是糖糖

构建一系列材料

相同行为 :

>>> for square in square_list(4):
...     print(square)
...
0
1
4
9
>>> for square in square_yield(4):
...     print(square)
...
0
1
4
9

不同的行为 :

成绩是单行:只有一次循环才能通过。当一个函数在其中产生产量时,我们把它称为发电机功能和一个振动器也就是它所返回的。这些术语是明亮的。我们失去了一个容器的方便,但获得了一系列的能量, 而这些能量是按需要计算, 并且任意地长。

成绩是懒惰,它会推迟计算计算。当你叫它时,它不会实际执行。返回函数返回振动器对象记得它留下的痕迹 每次你打电话next()转动器上(这发生在换行)行刑的几英寸向下一产地前进。return提高停止电流并结束序列( 这是循环的自然端 ) 。

成绩是多功能性。数据不必全部储存在一起,数据可以一次提供一次。数据可以是无限的。

>>> def squares_all_of_them():
...     x = 0
...     while True:
...         yield x * x
...         x += 1
...
>>> squares = squares_all_of_them()
>>> for _ in range(4):
...     print(next(squares))
...
0
1
4
9

需要时多个通行证系列剧不会太长,只是打个电话list()以下列方式:

>>> list(square_yield(4))
[0, 1, 4, 9]

最聪明的词选yield原因原因双两个意思应用 :

收益率生产或供应(如农业)

...在系列中提供下一个数据

收益率- 放弃或放弃(与政治权力一样)

...在传动器推进之前,将CPU执行。

其他回答

yield:

  • 可以通过停止函数从函数返回一个值多次。
  • 可使用from和它一样yield from.
  • 用于返回大数据时,将其分为小部分数据,以防止大量使用内存。

例如,test()可在以下返回'One', 'Two'['Three', 'Four']以一一一一一一一一一一一一一停止test()so so, so, so, so, so, so, so, so, so,test()停止返回共3倍test()总共3次:

def test():
    yield 'One'                  # Stop, return 'One' and resume 
    yield 'Two'                  # Stop, return 'Two' and resume
    yield from ['Three', 'Four'] # Stop and return ['Three', 'Four'] 

下面这三套代码可以调用test()打印和打印'One', 'Two', 'Three''Four':

for x in test():
    print(x)
x = test()
print(next(x))
print(next(x))
print(next(x))
print(next(x))
x = test()
print(x.__next__())
print(x.__next__())
print(x.__next__())
print(x.__next__())

其结果是:

$ python yield_test.py
One
Two
Three
Four

此外,在使用returnyield,没有办法从return:

def test():
    yield 'One' 
    yield 'Two'
    yield from ['Three', 'Four']
    return 'Five' # 'Five' cannot be got

x = test()
print(next(x))
print(next(x))
print(next(x))
print(next(x))
print(next(x)) # Here

因此,在试图获取'Five':

$ python yield_test.py 
One
Two
Three
Four
Traceback (most recent call last):
  File "C:\Users\kai\yield_test.py", line 12, in <module>
    print(next(x))
          ^^^^^^^
StopIteration: Five

所有的答案都是伟大的, 但对于新人来说有点困难。

我猜你已经学会了return语句。

作为类比,returnyield双胞胎。return意指“返回和停止”,而“真正”意指“返回,但继续”

  1. 尝试获得 num_ list 列表return.
def num_list(n):
    for i in range(n):
        return i

运行它:

In [5]: num_list(3)
Out[5]: 0

你看,你只得到一个数字 而不是他们的名单。return永远不允许你快乐地胜利, 仅仅一次执行,然后退出。

  1. 来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来来yield

替换returnyield:

In [10]: def num_list(n):
    ...:     for i in range(n):
    ...:         yield i
    ...:

In [11]: num_list(3)
Out[11]: <generator object num_list at 0x10327c990>

In [12]: list(num_list(3))
Out[12]: [0, 1, 2]

现在,你赢得了所有的数字。

return运行一次,停止一次,yield计划运行时间。您可以解释return计为return one of them, 和yield计为return all of them。这被称为iterable.

  1. 再来一步,我们可以改写yield声明的语中return
In [15]: def num_list(n):
    ...:     result = []
    ...:     for i in range(n):
    ...:         result.append(i)
    ...:     return result

In [16]: num_list(3)
Out[16]: [0, 1, 2]

这是核心yield.

列表之间的差别return输出和对象yield输出为 :

您将总是从列表对象中获取 [0, 1, 2] 列表对象, 但只能从“ 对象” 中获取它们yield输出一次。 所以, 它有一个新名称generator对象显示于Out[11]: <generator object num_list at 0x10327c990>.

最后,作为格罗克语的比喻:

  • returnyield双胞胎
  • listgenerator双胞胎

缩略yield关键字缩写为两个简单的事实:

  1. 如果汇编者检测到yield关键字任何地方函数内部的函数,该函数不再通过return语句。取代, 它, 它立即立即返回返回 a“等待列表”对象调用发电机
  2. 发电机是易用的,什么是易 易 易 性它的任何东西 像一个listsetrange或 dict-view, 带有按一定顺序视察每个要素的内建程序规程.

概括地说:最常见的情况是,a 发电机是一个懒惰、递增的待用清单。, 和yield语句允许您使用函数符号来编程列表值发电机应该逐渐吐出来此外,先进用途使你能够使用发电机作为共同路线(见下文)。

generator = myYieldingFunction(...)  # basically a list (but lazy)
x = list(generator)  # evaluate every element into a list

   generator
       v
[x[0], ..., ???]

         generator
             v
[x[0], x[1], ..., ???]

               generator
                   v
[x[0], x[1], x[2], ..., ???]

                       StopIteration exception
[x[0], x[1], x[2]]     done

基本上,当yield语句被遇到,函数暂停并保存状态,然后根据 python 传动协议发布“ 列表中下一个返回值” 。next()并捕获aStopIteration您可能遇到过发电机,例如:发电机表达式; 发电机功能更强大,因为您可以将参数反馈到暂停的发电机功能中,用它们来实施共同路线。稍后更多。


基本示例(“清单”)

让我们定义一个函数makeRange和皮松的一模一样range调用makeRange(n)将一个天才:

def makeRange(n):
    # return 0,1,2,...,n-1
    i = 0
    while i < n:
        yield i
        i += 1

>>> makeRange(5)
<generator object makeRange at 0x19e4aa0>

要迫使发电机立即返回其待处理值, 您可以将它传送到list()(就像你可以 任何可重复的):

>>> list(makeRange(5))
[0, 1, 2, 3, 4]

比较“仅返回列表”的示例

上述例子可视为仅仅是创建一份清单,并附在后面并返回:

# return a list                  #  # return a generator
def makeRange(n):                #  def makeRange(n):
    """return [0,1,2,...,n-1]""" #      """return 0,1,2,...,n-1"""
    TO_RETURN = []               # 
    i = 0                        #      i = 0
    while i < n:                 #      while i < n:
        TO_RETURN += [i]         #          yield i
        i += 1                   #          i += 1
    return TO_RETURN             # 

>>> makeRange(5)
[0, 1, 2, 3, 4]

不过,有一个重大差别;见最后一节。


您如何使用发电机

所有发电机都是易变的, 所以它们经常被这样使用:

#                  < ITERABLE >
>>> [x+10 for x in makeRange(5)]
[10, 11, 12, 13, 14]

为了对发电机有更好的感觉,你可以和发电机一起玩itertools模块 (必须使用)chain.from_iterable而不是chain例如,你甚至可能使用发电机来实施无穷无尽的懒惰清单,例如:itertools.count()您可以执行您自己的def enumerate(iterable): zip(count(), iterable),或者与yield时段循环中的关键字 。

请注意:发电机实际上可以用于更多的其他物品,例如:实施共同方案或非确定性编程或其他优雅的东西。 然而, 我在此展示的“ 懒惰列表” 观点是您最常用的 。


幕后幕后

这就是“ Python 迭代协议” 是如何工作的。 也就是说, 当您在list(makeRange(5))。这就是我刚才所说的“懒惰、递增清单”。

>>> x=iter(range(5))
>>> next(x)  # calls x.__next__(); x.next() is deprecated
0
>>> next(x)
1
>>> next(x)
2
>>> next(x)
3
>>> next(x)
4
>>> next(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

内置函数next()只需调用物体.__next__()函数,该函数是“终止协议”的一部分,并在所有迭代器中查找。您可以手动使用next()函数( 以及迭代协议的其他部分) 来实施花哨, 通常以降低可读性为代价, 所以尽量避免这样做...


锥体

锥体例如:

def interactiveProcedure():
    userResponse = yield makeQuestionWebpage()
    print('user response:', userResponse)
    yield 'success'

coroutine = interactiveProcedure()
webFormData = next(coroutine)  # same as .send(None)
userResponse = serveWebForm(webFormData)

# ...at some point later on web form submit...

successStatus = coroutine.send(userResponse)

共同常规(通常通过下列途径接受输入的发电机)yielde.g.nextInput = yield nextOutput,作为双向通信的一种形式)基本上是一种计算方法,它允许暂停自己并请求输入(例如,它下一步应该做什么)。当共程本身暂停时(当运行中的共程最终击中yield键,计算被暂停,控制被倒回“调用”功能(要求next暂停的生成器/ coutine 仍然暂停, 直到另一个引用函数( 可能是一个不同的函数/ 变量) 要求下一个值来取消它( 通常通过输入数据将暂停的逻辑内含引导到 coroutine 代码 ) 。

您可以将皮延共程视为懒惰的递增待决列表, 下一个元素不仅取决于先前的计算, 而且还取决于输入, 您可以选择在生成过程中注射 。


贫提亚e

通常,大多数人不会关心以下的区别,可能想在这里停止阅读。

在Python-speak语中,易 易 易 性中“理解“循环”概念的任意对象,如列表[1,2,3],和一个振动器是请求循环( 类似) 的具体实例[1,2,3].__iter__()A. A. A.发电机发电机与任何迭代器完全相同,但文字写法除外(用函数语法)。

当您从列表中请求一个迭代器时, 它会创建一个新的迭代器。 但是, 当您从一个迭代器中请求一个迭代器( 您很少会这样做 ) 时, 它只会给您一个副本 。

因此,在不可能的情况下,你没有 做这样的事情...

> x = myRange(5)
> list(x)
[0, 1, 2, 3, 4]
> list(x)
[]

...然后记住发电机是振动器;即,这是一次性使用。如果您想要重新使用它,您应该拨打myRange(...)如果您需要两次使用结果,将结果转换为列表并将其存储在变量中x = list(myRange(5))。那些绝对需要克隆生成器的人(例如,正在做可怕的黑化元方案化的人)可以使用itertools.tee (Python 3仍然在工作(如果绝对必要,自Python PEP 标准提案推迟审议。

缩略yieldPython 中的关键字用于退出代码而不干扰本地变量状态,当函数再次被称为“执行”时,从我们离开代码的最后一点开始。

以下示例说明yield:

def counter():
    x=2
    while x < 5:
        yield x
        x += 1
        
print("Initial value of x: ", counter()) 

for y in counter():
    print(y)

上述代码产生以下输出:

Initial value of x:  <generator object counter at 0x7f0263020ac0>
2
3
4

简单使用实例 :

>>> def foo():
    yield 100
    yield 20
    yield 3

    
>>> for i in foo(): print(i)

100
20
3
>>> 

如何运行 : 调用时, 函数会立即返回对象。 对象可以传递到下一个( ) 函数 。 当调用下一个( ) 函数时, 您的函数会一直运行到下一个产值, 并为下一个( ) 函数提供返回值 。

在引擎盖下, 循环确认对象是一个生成对象, 并使用下一个( ) 来获取下一个值 。

在一些语言中,比如ES6和更高语言中,它的实施略有不同, 所以下一个是生成对象的成员函数, 每次它得到下一个值时, 你就可以从调用器中传递数值。 所以如果结果是生成器, 那么你可以做类似y=结果。 ext( 555) , 而程序生成值可以说像 z = 产值 999 。 y 的值将是 999 , 下一个产值是 999, 而 z 的值将是 555 , 下一个产值是 555。 Python 获取并发送方法也有类似的效果 。