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

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 之后的语句 。 同样的程序会进一步重复 。

其他回答

yield简直就像return区别在于,下次你打电话给发电机时,从最后一次呼叫开始执行。yield与返回不同的语句,当生成时, 堆叠框架不会被清理, 但是控件会被转回调用方, 所以下次调用函数时, 它的状态将会恢复 。

对于您的代码,函数get_child_candidates动作就像一个循环器,这样当您扩展列表时,它会一次向新列表添加一个元素。

list.extend在你公布的代码样本中, 只需将图普还给列表, 并附加到列表中, 就会更加清晰 。

要理解的快捷键yield

当您看到一个函数yield语句,应用这个简单易懂的把戏来理解会发生什么:

  1. 插入一行result = []3⁄4 ̄ ̧漯B
  2. 替换各yield exprresult.append(expr).
  3. 插入一行return result函数的底部。
  4. - 耶 - 不再yield语句! 读取并找出代码 。
  5. 将函数与原始定义比较。

这个把戏也许能让你了解 函数背后的逻辑, 但实际发生什么了?yield与以列表为基础的方法发生的情况大不相同。 在许多情况下, 收益率方法会提高记忆效率和速度。 在其他情况下, 这个把戏会使你陷入无穷无尽的循环中, 即使最初的函数效果很好。 阅读更多来学习...

不要弄乱你的循环器 循环器和发电机

首先,动态自动交换协议- 当你写作时

for x in mylist:
    ...loop body...

Python 执行以下两个步骤:

  1. 获得一个循环器用于mylist:

    调调iter(mylist)->此返回一个带有next()方法(或)__next__()Python 3 中。

    [这是大多数人忘记告诉你的一步]

  2. 使用迭代器绕过项目 :

    继续叫next()从第1步返回的迭代器上的迭代器 方法上的迭代器 。next()指定用于x并执行环环体。如果有例外StopIteration从内部筹集next(),这意味着循环器中没有更多的值,循环就退出了。

真相是 Python 随时随地执行上述两步环绕环绕对象的内容 - 所以它可能是循环的, 但它也可以是代码otherlist.extend(mylist)(此处(此处)otherlist是 Python 列表)。

mylist易 易 易 性因为它执行了循环协议。在用户定义的类中,您可以执行__iter__()使类的示例可易易易操作的方法。 此方法应该返回振动器对象。next()两种方法都可实施。__iter__()next()在同一类同级同级同级同级同级同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同班同同同班同班同班同班同班同同班同班同班同班同班同班同同同班同班同班同班同班同同班同同同同同班同班同班同班同同班同班同班同班同同同同同同同班同班同班同同同同同同同班同同同同同同班同__iter__()返回返回self。这将对简单案例有效,但当您想要两个迭代器同时绕过同一个对象时,则不会有效。

这就是传动程序,许多物体执行这个程序:

  1. 内置列表、词典、图普尔、设置和文件。
  2. 执行的用户定义的分类__iter__().
  3. 发电机。

注 afor循环不知道它处理的是什么样的物体 - 它只是遵循循环程序, 并且很乐意按项目逐项获得它调用的项目next(). 内置清单逐项归还其物项,词典则逐项归还键键一个一个一个一个,文件返回线条一个一个一个一个一个,等等。 和发电机返回。 。 。yield输入 :

def f123():
    yield 1
    yield 2
    yield 3

for item in f123():
    print item

取代yield如果您有三种语句return以 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国 国f123()只有第一个被执行, 而功能会退出。 但是,f123()没有普通函数为普通函数的普通函数为普通函数。f123()被召唤的,被召唤的,被召唤的,被召唤的,返回输出语句中的任何值。它返回生成对象。它返回一个生成对象。此外,函数并不真正退出 -它进入中止状态。当for循环试图环绕到发电机对象上, 函数从中止状态恢复 。yield执行下一行代码,在此情况下,ayield语句,然后返回该语句,作为下一个项目返回该语句。这种情况发生到函数退出时,然后生成器产生StopIteration,并循环出口。

因此,发电机对象有点像一个适配器—— 一方面,它展示了迭代程序,通过曝光__iter__()next()保存for循环快乐。 但是,在另一端, 它运行的函数足够从中获取下一个值, 并将其重新置于暂停模式 。

为什么使用发电机?

通常情况下, 您可以写入不使用发电机的代码, 但使用相同的逻辑逻辑。 一个选项是使用我之前提到的临时列表“ trick ” 。 这不会在所有情况下都有效, 例如, 如果您有无限循环, 或者当您有很长的列表时它可能无效地使用内存 。 另一种方法是执行一个新的可循环的类“ 某些东西 ” , 将国家保留在成员中, 并在成员中执行下一个逻辑步骤 。next()(或)__next__()Python 3 方法中的代码 。 取决于逻辑, 内部的代码 。next()方法最终可能会看起来非常复杂,容易出现虫子。 这里的发电机提供了清洁和容易的解决方案。

在皮顿generators(一种特殊类型的iterators)用于产生一系列数值和yield关键字就和return生成功能关键字。

另一件有趣的事yield关键字在保存statea 发电机功能.

所以,我们可以设定number每次对一个不同的值generator产值。

以下是一个例子:

def getPrimes(number):
    while True:
        if isPrime(number):
            number = yield number     # a miracle occurs here
        number += 1

def printSuccessivePrimes(iterations, base=10):
    primeGenerator = getPrimes(base)
    primeGenerator.send(None)
    for power in range(iterations):
        print(primeGenerator.send(base ** power))

简言之,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 ” , 它会继续这样下去, 直到条件返回错误, 发电机跳到函数结束 。

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

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