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链接。
简单解答
当函数包含至少一个输出语句时,函数自动成为生成函数。当您调用生成函数时, python 在生成函数中执行代码,直到生成语句发生。 当您调用生成函数时, python 继续从冻结位置执行生成函数中的代码,直到生成语句发生反复发生。 生成函数执行代码,直到生成函数在没有生成语句的情况下运行结束。
基准基准基准基准基准基准基准
创建列表并返回它 :
def my_range(n):
my_list = []
i = 0
while i < n:
my_list.append(i)
i += 1
return my_list
@profile
def function():
my_sum = 0
my_values = my_range(1000000)
for my_value in my_values:
my_sum += my_value
function()
结果有:
Total time: 1.07901 s
Timer unit: 1e-06 s
Line # Hits Time Per Hit % Time Line Contents
==============================================================
9 @profile
10 def function():
11 1 1.1 1.1 0.0 my_sum = 0
12 1 494875.0 494875.0 45.9 my_values = my_range(1000000)
13 1000001 262842.1 0.3 24.4 for my_value in my_values:
14 1000000 321289.8 0.3 29.8 my_sum += my_value
Line # Mem usage Increment Occurences Line Contents
============================================================
9 40.168 MiB 40.168 MiB 1 @profile
10 def function():
11 40.168 MiB 0.000 MiB 1 my_sum = 0
12 78.914 MiB 38.746 MiB 1 my_values = my_range(1000000)
13 78.941 MiB 0.012 MiB 1000001 for my_value in my_values:
14 78.941 MiB 0.016 MiB 1000000 my_sum += my_value
在飞行上生成值 :
def my_range(n):
i = 0
while i < n:
yield i
i += 1
@profile
def function():
my_sum = 0
for my_value in my_range(1000000):
my_sum += my_value
function()
结果有:
Total time: 1.24841 s
Timer unit: 1e-06 s
Line # Hits Time Per Hit % Time Line Contents
==============================================================
7 @profile
8 def function():
9 1 1.1 1.1 0.0 my_sum = 0
10
11 1000001 895617.3 0.9 71.7 for my_value in my_range(1000000):
12 1000000 352793.7 0.4 28.3 my_sum += my_value
Line # Mem usage Increment Occurences Line Contents
============================================================
7 40.168 MiB 40.168 MiB 1 @profile
8 def function():
9 40.168 MiB 0.000 MiB 1 my_sum = 0
10
11 40.203 MiB 0.016 MiB 1000001 for my_value in my_range(1000000):
12 40.203 MiB 0.020 MiB 1000000 my_sum += my_value
摘要摘要摘要
生成器函数需要稍多一点时间来执行, 而不是返回列表但少用内存的函数 。
收益率和返回一样, 它会返回任何您告诉它的东西( 作为生成器 ) 。 区别在于下次您调用生成器时, 执行从最后一次调用开始到收益语句 。 与返回不同的是, 当收益发生时, 堆叠框架不会被清理, 但是控制会被转回调回调用方, 因此下次调用函数时, 它的状态将会恢复 。
在您的代码中,函数获取_child_camedates 的动作就像一个迭代器,这样当您扩展列表时,它会一次在新列表中添加一个元素 。
列表。extendend calls a plerator until it's fulled it's explator until. 如果是您所贴的代码样本, 只需将图普还给列表, 并附加到列表中, 就会更加清楚 。
就像有人要你做5个纸杯蛋糕一样。如果你做了至少一个纸杯蛋糕,你可以在做其他蛋糕时给他们吃。
In [4]: def make_cake(numbers):
...: for i in range(numbers):
...: yield 'Cake {}'.format(i)
...:
In [5]: factory = make_cake(5)
这里称为发电机, 它会做蛋糕。 如果您叫作 Make_ 函数, 您可以得到一个发电机, 而不是运行此函数。 这是因为当输出关键字出现在一个函数中时, 它会变成一个生成器 。
In [7]: next(factory)
Out[7]: 'Cake 0'
In [8]: next(factory)
Out[8]: 'Cake 1'
In [9]: next(factory)
Out[9]: 'Cake 2'
In [10]: next(factory)
Out[10]: 'Cake 3'
In [11]: next(factory)
Out[11]: 'Cake 4'
他们消耗了所有的蛋糕, 但他们又要求一个。
In [12]: next(factory)
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-12-0f5c45da9774> in <module>
----> 1 next(factory)
StopIteration:
并且他们被告知不要问更多的问题。 所以一旦你消耗了发电机, 你就会用它做。 如果你想要更多的蛋糕,你需要再打电话做蛋糕。 这就像再订一份蛋糕。
In [13]: factory = make_cake(3)
In [14]: for cake in factory:
...: print(cake)
...:
Cake 0
Cake 1
Cake 2
您也可以使用上面的生成器来循环。
举个例子:假设你每次问密码时都想要随机密码。
In [22]: import random
In [23]: import string
In [24]: def random_password_generator():
...: while True:
...: yield ''.join([random.choice(string.ascii_letters) for _ in range(8)])
...:
In [25]: rpg = random_password_generator()
In [26]: for i in range(3):
...: print(next(rpg))
...:
FXpUBhhH
DdUDHoHn
dvtebEqG
In [27]: next(rpg)
Out[27]: 'mJbYRMNo'
这里的 rpg 是一个生成器, 它可以生成无限数量的随机密码。 所以我们也可以说, 当我们不知道序列的长度时, 生成器是有用的, 不同于列表, 列表中有一定数量的元素 。
从方案拟订的角度来看,迭代器是作为散装件执行的。
为实施同时执行的迭代器、发电机和线形集合等,人们使用发往有调度员的关闭对象的电文,用发件人对“信息”的回答。
"下一步"是给一个封口发送的信息 由"标准"电话创建
有多种方法可以实施此计算。 我使用了突变, 但可以通过返回当前值和下一个生成者( 使其具有优先透明度 ) , 进行这种不发生突变的计算。 鼠标使用一些中间语言对初始程序进行一系列转换, 其中之一是将产出操作者转换为使用更简单的操作员的某种语言。
这是如何重写产量的演示, 它使用 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 - >