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链接。


当前回答

要理解它的产值函数,人们必须理解发电机是什么。此外,在理解发电机之前,你必须理解易用的东西。易用 : 易用 : 要创建列表, 您自然需要能够逐个读取每个元素。 逐项读取其项目的过程被称为迭代 :

>>> mylist = [1, 2, 3]
>>> for i in mylist:
...    print(i)
1
2
3 

My list 是可替换的。 当您使用列表理解值时, 您会创建一个列表, 因此该列表是可替换的 :

>>> mylist = [x*x for x in range(3)]
>>> for i in mylist:
...    print(i)
0
1
4 

所有可用于... 的数据结构都是可循环的; 列表、 字符串、 文件...

这些惯用方法很方便,因为您可以随意阅读,但您可以将所有值存储在记忆中,当您有许多值时,这些值并不总是可取的。 生成器: 生成器 A 也是一种迭代器, 一种特殊的迭代器, 只能迭代一次。 生成器不会将所有值存储在记忆中, 而是在苍蝇上生成值 :

发电机:发电机、发电机、发电机发电,但不储存能源;)

>>> mygenerator = (x*x for x in range(3))
>>> for i in mygenerator:
...    print(i)
0
1
4 

只要使用 () 而不是 [] , 列表理解就会变成发电机理解。 但是, 由于发电机只能使用一次, 您无法在我的生成器中执行 i 第二次 : 生成器计算 0, 然后丢弃它, 然后计算 1, 最后一次计算 4 。 典型的黑色盲人打破玉米 。

产出关键字的使用方式与返回相同,但函数返回生成器。

>>> def createGenerator():
...    mylist = range(3)
...    for i in mylist:
...        yield i*i
...
>>> mygenerator = createGenerator() 
>>> print(mygenerator) 
<generator object createGenerator at 0xb7555c34>
>>> for i in mygenerator:
...     print(i)
0
1
4 

这个例子本身是毫无用处的,但是当您需要函数返回大量数值,而只需要读一次,使用产量就方便了。

要掌握收益率,需要清楚的是,当函数被调用时,函数正文中写入的代码将不会运行。函数只返回生成对象。启动者可能会对此感到困惑。

第二,明白代码会从每次使用发电机时留下的代码中继续使用。

现在最困难的部分是:

第一次调用您函数所创建的生成器对象时, 它会运行函数中的代码, 从开始一直运行到产生, 然后返回循环的第一个值。 然后, 以后的每次调用都会运行您在函数中写入的循环的下一个迭代, 并返回下一个值。 这将一直持续到生成器被视为空, 当函数运行时没有被击中时该生成。 这可能是因为循环已经结束, 或者因为您不再满足于“ if/ else ” 。

个人理解 我希望帮助你!

其他回答

从方案拟订的角度来看,迭代器是作为散装件执行的。

为实施同时执行的迭代器、发电机和线形集合等,人们使用发往有调度员的关闭对象的电文,用发件人对“信息”的回答。

"下一步"是给一个封口发送的信息 由"标准"电话创建

有多种方法可以实施此计算。 我使用了突变, 但可以通过返回当前值和下一个生成者( 使其具有优先透明度 ) , 进行这种不发生突变的计算。 鼠标使用一些中间语言对初始程序进行一系列转换, 其中之一是将产出操作者转换为使用更简单的操作员的某种语言。

这是如何重写产量的演示, 它使用 R6RS 的结构, 但语义与 Python 的相同 。 这是相同的计算模式, 只需要修改语法, 才能使用 Python 的 产量重写 。

- (define gen (lambda (l) (define gen (lambda (l)) (define emple (lambda (lambda () ()) (if (null? l)) 'END (let ((v (car l))(set))(l (cdr))) (lambda (m) (cket m) (case m ('yield (yeld)(yeld))('ield))('iint (lamb) (lambda (lab) (lambda (data) (data) (l data))) ())) ) - (define 流 (gen 'ield (gen'(1,2 3 ) )) - (流 (流 ield) ) ) - (Live END - (Slead) (流 (流 ) (流 ) (流 (流 流 (流 流 流 流 流 流 ) 'ield) 'end - >

我本打算张贴“Beazley的“Python:基本参考”第19页,

另外,请注意, 产量可以作为发电机功能中的双重用途, 共程中可以使用。 虽然这与您的代码片断不相同, 但( ield) 也可以用作函数中的表达方式。 当调用者使用发送( ) 方法给方法发送一个值时, 共程将执行到遇到下一个( yeld) 语句时 。

生成器和共同路由是建立数据流类型应用程序的很酷的方法。 我认为值得知道在函数中产出语句的另一种用途。

通常情况下, 它会用来创建一个不起作用的代名词。 将“ ield” 当作您函数的附加件, 以及您作为数组的函数。 如果符合某些标准, 您可以在函数中添加此值, 使之成为代名词 。

arr=[]
if 2>0:
   arr.append(2)

def func():
   if 2>0:
      yield 2

两者的输出结果相同。

使用产量的主要优势是创建迭代器。 迭代器在即时计算时不会计算每个项目的价值。 它们只在您要求时才计算。 这被称为懒惰评价 。

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

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概念之间的对应关系。

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

我打电话给你并告诉你,我想要一个以特定方式计算的数字序列,我告诉你算法是什么。 这个步骤对应着定义发电机的函数, 也就是包含一个产出的函数。 稍后我告诉你, “ 好, 准备好告诉我数字的序列 ” 。 这个步骤对应着调用发电机的函数, 返回一个发电机对象。 注意不要告诉我任何数字; 你只是拿起你的纸张和铅笔。 我问你, “ 请告诉我下一个数字 ” , 然后你告诉我第一个数字; 之后, 你等着我问你下一个数字。 这是你的任务, 也就是确定你所在的位置, 你已经说过的数字, 下一个数字是什么。 我不在乎细节。 这个步骤相当于在发电机对象上调用下一个( 发电机) 号码的方法。 ( Python 2, next) 注意, 这是一个发电机对象的方法; 在 Python 3, 它被命名为...

这是生成器所做的( 包含一个产值的函数 ) ; 它开始在第一个( ) 上执行, 当它做一个产值时暂停, 当要求下一个( ) 值时, 它会从最后一点继续 。 它的设计完全符合 Python 的循环协议, 协议描述如何按顺序要求值 。

迭代协议最著名的用户是 Python 的命令用户。 所以, 当你做 :

for item in sequence:

序列是否是一个列表、字符串、字典或上述生成对象并不重要;结果是一样的:您逐个阅读序列中的项目。

请注意,定义含有产出关键字的函数不是创建生成器的唯一方法;它只是创建生成器的最简单的方法。

欲知更准确的信息,请阅读Python文件中的迭代机类型、产量说明和发电机。