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

当前回答

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

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);

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

其他回答

佩顿有什么差错?

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

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

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

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

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

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

在描述如何使用发电机的许多伟大答案中, 我感到还没有给出一种答案。 这是编程语言理论的答案:

缩略yieldPython 语句中的 Python 语句返回一个发电机。 Python 中的发电机是一个函数返回续续(具体地说,是一种共同的例行公事,但延续是了解情况的一般机制)。

编程语言理论的继续是更根本的计算方法,但通常不会被使用,因为它们极难解释,也很难执行。但是,关于继续的理念很简单:是计算状态尚未完成。在这种状态下,变量的当前值、尚未执行的操作等等被保存。然后,在程序稍后的某个时候,可以援引继续,使程序的变量被重新设置到状态,保存的操作被执行。

以这种更一般性的形式出现的延续可以采取两种方式实施。call/cc方式,程序堆放的堆放实际上被保存, 当继续被引用时, 堆放的堆放就会被恢复 。

在继续传承风格(CPS)中,续编只是程序员明确管理和传到子例程的正常功能(仅在功能为头等语言的语文中),程序员明确管理和传到子例程。在这种风格中,程序状态代表关闭(和恰好在其中编码的变量),而不是堆叠中某处的变量。 管理控制流程的功能接受继续作为参数(在CPS的某些变异中,功能可能接受多重延续),并通过仅拨打这些函数来操纵控制流程,然后返回。一个非常简单的延续传承风格实例如下:

def save_file(filename):
  def write_file_continuation():
    write_stuff_to_file(filename)

  check_if_file_exists_and_user_wants_to_overwrite(write_file_continuation)

在此(非常简单化的)示例中,程序员将实际写入文件的操作保存为续存(这有可能是一个非常复杂的操作,有许多细节要写出来),然后将这一续存(即作为头等关闭)传递给另一个操作员,该操作员会做一些更多的处理,然后在必要时调用它。 (在实际的 GUI 编程中,我大量使用这种设计模式,要么是因为它可以节省我的代码线,要么更重要的是,在图形用户界面事件触发后管理控制流程。 )

这个职位的其余部分将不失为一般性,将连续性概念化为CPS, 因为它很容易理解和阅读。


现在让我们来谈谈Python的发电机。发电机是一个特定的子类型 继续。而一般而言,继续保留能够拯救a计算计算(即程序调用堆叠)发电机只能保存电离层的迭代状态。振动器虽然这一定义对发电机的某些使用情况略有误导性,例如:

def f():
  while True:
    yield 4

这显然是一个合理的可循环性, 其行为是明确定义的, 每当发电机转动时, 它就会返回 4 个( 并且永远这样做 ) 。 但是,在思考迭代器时, 可能不会想到这种典型的可循环性( 即, , ) 。for x in collection: do_something(x)这个例子说明了发电机的功率:如果有什么是迭代器,发电机可以挽救其迭代状态。

需要重申: 继续可以保存程序堆叠的状态, 发电机可以保存循环状态。 这意味着, 继续的威力比发电机大得多, 并且发电机也容易得多, 也容易得多。 语言设计师更容易执行, 程序设计员更容易使用( 如果您有时间燃烧, 试着阅读和理解)此页面的续续和调用/ cc).

但您可以很容易地实施(和概念化)发电机,作为延续传承风格的一个简单而具体的例子:

时 时 时yield被调用,它告诉函数返回一个延续。当再次调用函数时,它从它离开的开始。因此,在假假假代码(即不是伪代码,但不包括代码)中,生成器的next方法基本上如下:

class Generator():
  def __init__(self,iterable,generatorfun):
    self.next_continuation = lambda:generatorfun(iterable)

  def next(self):
    value, next_continuation = self.next_continuation()
    self.next_continuation = next_continuation
    return value

位于yield关键字实际上是实际生成功能的合成糖, 基本上类似 :

def generatorfun(iterable):
  if len(iterable) == 0:
    raise StopIteration
  else:
    return (iterable[0], lambda:generatorfun(iterable[1:]))

记住这只是假代号,而Python发电机的实际安装则更为复杂。 但是,作为了解正在发生的情况的一种练习,试图在不使用发电机物体的情况下,使用持续的传承风格来实施发电机物体。yield关键字。

简言之,yield语句将函数转换为生产特殊物体的工厂generator环绕您原始函数的正文。当generator被迭代,它执行您函数,直到到达下一个yield然后暂停执行执行,然后对传递到yield。在每次迭代上重复这个过程,直到执行路径退出函数。例如,

def simple_generator():
    yield 'one'
    yield 'two'
    yield 'three'

for i in simple_generator():
    print i

简单产出

one
two
three

电源来自使用循环计算序列的生成器, 生成器执行循环每次停止到“ ield ” 的下一个计算结果, 这样它就可以计算飞行上的列表, 好处是存储到特别大的计算中的内存

说你想创造你自己的range函数产生可循环的数字范围,可以这样做,

def myRangeNaive(i):
    n = 0
    range = []
    while n < i:
        range.append(n)
        n = n + 1
    return range

并像这样使用它;

for i in myRangeNaive(10):
    print i

但这效率低,因为

  • 您创建了一个只使用一次的数组( 此废物内存)
  • 这个代码实际上绕过那个阵列两次! ! : () ! () ! ()

幸好吉多和他的团队 慷慨地开发了发电机 这样我们就可以这么做了

def myRangeSmart(i):
    n = 0
    while n < i:
       yield n
       n = n + 1
    return

for i in myRangeSmart(10):
    print i

在每次迭代时,发电机上有一个功用,next()执行函数,直到它到达“当”语句,停止该语句和“当”语句,停止该语句和“当”值,或者到达函数的结尾。在此情况下,第一次调用时,next()执行到输出语句并产生“ n ” , 下次调用时, 它会执行递增语句, 跳回“ 同时” , 评估它, 如果真的, 它会停止并产生“ n ” , 它会继续这样下去, 直到条件返回错误, 发电机跳到函数结束 。

yield函数的返回元素。区别是,yield将一个元素转换成一个生成器。一个生成器的行为就像一个函数,直到某东西“当”为“当”为止。发电机停止直到下一个调用,并且从与开始的完全相同的点继续。您可以通过调用所有“当”值的序列,从一个角度获得所有“当”值的序列。list(generator()).

许多人使用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()给发电机。

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