何为使用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 。barcode_generator以生成框中独有的序列号。 显然,您可以通过函数返回大量这样的条形码,但受硬件(RAM)的限制。 更明智和空间效率更高的选项是按需生成这些序列号。

机器代码 :

def barcode_generator():
    serial_number = 10000  # Initial barcode
    while True:
        yield serial_number
        serial_number += 1


barcode = barcode_generator()
while True:
    number_of_lightbulbs_to_generate = int(input("How many lightbulbs to generate? "))
    barcodes = [next(barcode) for _ in range(number_of_lightbulbs_to_generate)]
    print(barcodes)

    # function_to_create_the_next_batch_of_lightbulbs(barcodes)

    produce_more = input("Produce more? [Y/n]: ")
    if produce_more == "n":
        break

注注:next(barcode)位数。

如你所可以看到,我们有一个自成一体的“功能” 每次生成下一个独特的序列号。此函数返回发电机发电机正如你可以看到的,我们不是每次需要新序列号时都调用这个功能,而是在使用新序列号。next()给发电机提供下一个序列号。

低拉隔热器

更确切地说,这个发电机是懒惰的滚动器迭代器是一个能帮助我们穿越物体序列的物体。 它被称为懒惰因为它在需要之前不会在内存中装入序列的全部项目。next在上一个示例中,直 直 直从迭代器获取下一个项目。内含循环方式正在使用 :

for barcode in barcode_generator():
    print(barcode)

这将无穷尽地打印条形码, 但你不会失去内存 。

换句话说,发电机看起来像a 函数但行为举止如迭代器。

现实世界应用?

最后, 真实世界应用程序 。 当您在大序列中工作时, 它们通常有用 。 想象一下读取巨大从含有数十亿记录的磁盘文件中取出文件。 在您能够处理其内容之前, 在内存中读取整个文件, 可能会不可行( 也就是说, 您会用完内存 ) 。

其他回答

yield用于创建generator。如果将生成器视为一个迭代器,每个迭代都会给您带来价值。当您在循环中使用收益率时,会得到一个生成对象,您可以用该对象从循环中以迭接方式从循环中获取项目

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

下面是浅白语言的例子。我将提供高层次人类概念与低层次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 文档中。

这是关于什么的心理形象yield确实如此。

我想把一条线视为有堆叠(即使它不是用这种方式执行的)。

当调用一个普通函数时, 它会将其本地变量放入堆栈, 进行一些计算, 然后清除堆栈和返回。 其本地变量的值再也不会被看到 。

yield函数,当其代码开始运行时(即函数被调用后,返回一个生成对象,该生成对象next()然后引用方法),它同样将其本地变量放在堆叠上,并计算一段时间。但是当它击中yield语句,在清理其部分堆叠并返回之前,它先对本地变量进行速记,然后将其存储在生成器对象中。它还写下它目前在其代码中的位置(即特定yield声明))

所以这是一种冷冻功能 发电机挂在了上面

何时next()函数随后被调用, 它从堆叠上取回函数的物品, 并重新激活它。 函数继续从剩余部分进行计算, 忽略了它刚刚在冷藏中度过了永恒时间的事实 。

比较以下实例:

def normalFunction():
    return
    if False:
        pass

def yielderFunction():
    return
    if False:
        yield 12

当我们调用第二个函数时,它的行为与第一个功能非常不同。yield声明可能无法取得, 但如果它存在任何地方, 它会改变我们所处理的事物的性质。

>>> yielderFunction()
<generator object yielderFunction at 0x07742D28>

电 电 电yielderFunction()(也许用它来命名这种东西是个好主意)yielder可读性前缀。 )

>>> gen = yielderFunction()
>>> dir(gen)
['__class__',
 ...
 '__iter__',    #Returns gen itself, to make it work uniformly with containers
 ...            #when given to a for loop. (Containers return an iterator instead.)
 'close',
 'gi_code',
 'gi_frame',
 'gi_running',
 'next',        #The method that runs the function's body.
 'send',
 'throw']

缩略gi_codegi_frame字段中存储冻结状态的字段。dir(..),我们可以确认 我们的心理模式 上面是可信的。

放弃是一个对象

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

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

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

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

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

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