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

当前回答

我不太熟悉Python, 但我相信它和Python一样C# 的迭代器区块如果你熟悉这些。

关键的想法是,编译者/解释者/ 不论做什么诡计, 就打电话者而言, 他们可以继续拨打下一个 () , 它会继续返回数值 :仿佛发电机方法被暂停。现在显然你无法真正“暂停”一种方法,因此编译器可以建立一个状态机器,以便你记住你目前的位置和本地变量等的外观。这比自己写一个转动器容易得多。

其他回答

下面是浅白语言的例子。我将提供高层次人类概念与低层次Python概念之间的对应关系。

我想用数字序列操作, 但我不想用这个序列的创建来烦恼我自己, 我只想专注于我想做的操作。 因此, 我做以下工作:

  • 我打电话给你,告诉你,我想要一个数字序列 以特定的方式计算, 我让你知道算法是什么。
    此步骤对应于def内插入发电机函数,即包含yield.
  • 稍后,我告诉你, "好了,准备好告诉我数字的顺序"。
    此步骤对应于调用发电机函数, 以返回发电机对象 。注意不要告诉我任何数字 你只要拿起你的纸和铅笔
  • 我问你,"告诉我下一个号码",然后你告诉我第一个号码, 在那之后,你等我问你下一个号码。你的工作是记住你在哪里,你已经说过什么号码,下一个号码是什么。 我不在乎细节。
    此步骤对应于调用next(generator)在发电机的物体上。
    (在Python 2,.next是产生器物体的一种方法;在Python 3中,它被命名为.__next__,但正确的称呼方式是使用内置next()函数类似len().__len__)
  • ...重复前一步,直到...
  • 最终,你可能会走到尽头。你不会告诉我一个数字;你只会喊叫,“抓住你的马!我受够了!不再有数字了!”
    此步骤对应于生成器对象结束工作, 并提升StopIteration例外。
    生成器函数不需要提出例外。 当函数结束或发布时自动生成 。return.

这就是发电机(包含yield;它开始执行第一个next()时暂停yield,当要求next()它从最后一点继续值 。 它的设计完全符合 Python 的迭代协议, 它描述了如何按顺序请求值 。

循环程序最著名的用户是for在 Python 中命令。 所以, 当您做 :

for item in sequence:

这不重要,如果sequence是列表、字符串、字典或生成器对象对象如上文所述;结果相同:您逐个阅读顺序中的项目。

请注意def函数内含有yield关键字不是创建生成器的唯一方法; 它只是创建生成器的最简单的方法 。

将 " 更准确的信息 " 改为 " 更准确的信息 "迭代器类型、、 和收益单报表发电机发电机在 Python 文档中。

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执行。

python 的输出与返回语句类似,但有些差异除外。如果要从函数返回多个值,返回语句将把所有值都作为列表返回,并将其存储在调用符块的内存中。但如果我们不想使用额外的内存,会怎样?相反,我们需要在需要时从函数中获取该值。这是产出的来源。考虑以下函数:

def fun():
   yield 1
   yield 2
   yield 3

打电话的人是:

def caller():
   print ('First value printing')
   print (fun())
   print ('Second value printing')
   print (fun())
   print ('Third value printing')
   print (fun())

上述代码段(调用函数),如果调用,产出:-

First value printing
1
Second value printing
2
Third value printing
3

从上文可以看出, 产出返回其调用器的值, 但当函数再次调用时, 它不会从第一个语句开始, 而是从产出后右侧的语句开始。 在上述示例中, “ 第一值打印” 打印, 函数被调用。 1 被回传并打印。 然后, 打印“ 第二值打印” , 并再次调用有趣 () 。 它不打印 1 (第一个语句) , 而是返回 2 , 也就是说, 仅从产出 1 之后的语句 。 同样的程序会进一步重复 。

还有一件事情要提: 产量的函数其实不一定要终止。我写了这样的代码:

def fib():
    last, cur = 0, 1
    while True: 
        yield cur
        last, cur = cur, last + cur

这样我就可以用在别的代码里了

for f in fib():
    if some_condition: break
    coolfuncs(f);

它确实有助于简化一些问题,使一些事情更容易处理。

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

我猜你已经学会了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双胞胎