Python 中产出关键字的用法是什么? 它能做什么?

例如,我试图理解这个代码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_camedates 被调用时会怎样? 列表是否返回? 单一个元素吗? 是否再次调用? 以后的电话何时停止?


1. 本代码由Jochen Schulz(jrschulz)编写,他为公制空间制作了一个伟大的Python图书馆,与完整的源:模块mspace链接。


当前回答

发电机可以使个别经过处理的物品立即得到处理(不必等待整个收集过程的处理),下面的例子说明了这一点。

import time

def get_gen():
    for i in range(10):
        yield i
        time.sleep(1)

def get_list():
    ret = []
    for i in range(10):
        ret.append(i)
        time.sleep(1)
    return ret


start_time = time.time()
print('get_gen iteration (individual results come immediately)')
for i in get_gen():
    print(f'result arrived after: {time.time() - start_time:.0f} seconds')
print()

start_time = time.time()
print('get_list iteration (results come all at once)') 
for i in get_list():
    print(f'result arrived after: {time.time() - start_time:.0f} seconds')

get_gen iteration (individual results come immediately)
result arrived after: 0 seconds
result arrived after: 1 seconds
result arrived after: 2 seconds
result arrived after: 3 seconds
result arrived after: 4 seconds
result arrived after: 5 seconds
result arrived after: 6 seconds
result arrived after: 7 seconds
result arrived after: 8 seconds
result arrived after: 9 seconds

get_list iteration (results come all at once)
result arrived after: 10 seconds
result arrived after: 10 seconds
result arrived after: 10 seconds
result arrived after: 10 seconds
result arrived after: 10 seconds
result arrived after: 10 seconds
result arrived after: 10 seconds
result arrived after: 10 seconds
result arrived after: 10 seconds
result arrived after: 10 seconds

其他回答

输出是函数的返回元素。 区别在于, 产出元素将函数转换成生成器。 生成器的行为就像一个函数, 直到某种“ 归属 ” 。 生成器停止直到下一次调用, 并且从与开始的完全相同的点继续。 您可以通过调用列表( 生成器 () ) 获得一个序列中所有“ 属性” 值的序列。

对于那些更喜欢最低限度工作实例的人来说,考虑一下这次交互式的Python会议:

>>> def f():
...   yield 1
...   yield 2
...   yield 3
... 
>>> g = f()
>>> for i in g:
...   print(i)
... 
1
2
3
>>> for i in g:
...   print(i)
... 
>>> # Note that this time nothing was printed

失败给了你一台发电机

def get_odd_numbers(i):
    return range(1, i, 2)
def yield_odd_numbers(i):
    for x in range(1, i, 2):
       yield x
foo = get_odd_numbers(10)
bar = yield_odd_numbers(10)
foo
[1, 3, 5, 7, 9]
bar
<generator object yield_odd_numbers at 0x1029c6f50>
bar.next()
1
bar.next()
3
bar.next()
5

正如你可以看到的那样,在第一种情况下,Foo同时持有完整的记忆列表。对于包含5个元素的清单来说,这不是什么大不了的事,但是如果你想列出500万个元素的清单,那又会怎样?这不仅仅是一个巨大的记忆食用器,在函数被调用的时候,它还要花费很多时间来构建这个功能。

在第二种情况下, 酒吧只给您一台发电机。 发电机是一个可循环的, 意思是您可以在循环中使用它, 等等, 但每个值只能存取一次。 所有值也并非同时存储在记忆中; 生成器的“ 成员” 对象, 上次您称之为“ 成员” 时, 它在循环中。 这样, 如果您使用一个可( 说) 的转号, 计数为500亿, 你不必一次数到500亿, 然后存储500亿的数值来进行计算。

再者,这是一个相当巧妙的例子,如果你真想数到500亿,你可能会使用滑板。 () :

这是发电机中最简单的使用实例。 正如您所说, 它可以用来写高效的变换, 使用产量将东西推到调用堆叠上, 而不是使用某种堆叠变量。 发电机也可以用于专门的树道, 以及各种其它方式 。

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

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 生成器( 一种特殊的迭代器) 中, 生成一系列的值, 产出关键字与 发电机功能的返回关键字相似 。

另一个令人着迷的是 生成关键词的方法 是保存生成功能的状态。

因此,我们可以设定一个数字 以不同的数值 每一次发电机产生时。

以下是一个例子:

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