何为使用yield
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_candidates
是否调用 ? 列表是否返回 ? 单元素 ? 是否又调用 ? 以后的呼叫何时停止 ?
1. 本代码由Jochen Schulz(jrschulz)编写,他为公制空间制作了一个伟大的Python图书馆。模块 m 空间.
在皮顿generators
(一种特殊类型的iterators
)用于产生一系列数值和yield
关键字就和return
生成功能关键字。
另一件有趣的事yield
关键字在保存state
a 发电机功能.
所以,我们可以设定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
就像有人要你做5个蛋糕。如果你做了至少一个蛋糕, 你可以在做其他蛋糕的时候给他们吃。
In [4]: def make_cake(numbers):
...: for i in range(numbers):
...: yield 'Cake {}'.format(i)
...:
In [5]: factory = make_cake(5)
给factory
称为“发电机”的发电机,它使你们做蛋糕。如果你们打电话,make_function
,而不是运行此函数。这是因为当yield
关键字在函数中,它成为生成器。
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:
有人命令他们不要多问一些问题。一旦你消耗了一台发电机,你就用完它了。你应当打电话,make_cake
如果你想要更多蛋糕,就再来一次。这就像给蛋糕再订一份蛋糕一样。
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
是一个生成器, 它可以生成无限数量的随机密码。 所以我们也可以说, 当我们不知道序列的长度时, 生成器是有用的, 而不是列表中含有数量有限的元素 。
也可以将数据发送回生成器!
事实上,正如这里许多答案所解释的,使用yield
创建 a 创建generator
.
您可以使用yield
关键字到将数据发送回“ 实时” 生成器.
示例:
假设我们有一种方法可以从英语翻译成其他语言。 在开始的时候, 它会做一些很重的事情, 应该做一次。 我们希望这个方法可以永远运行( 不知道为什么..... . :) , 并且收到要翻译的单词 。
def translator():
# load all the words in English language and the translation to 'other lang'
my_words_dict = {'hello': 'hello in other language', 'dog': 'dog in other language'}
while True:
word = (yield)
yield my_words_dict.get(word, 'Unknown word...')
运行中 :
my_words_translator = translator()
next(my_words_translator)
print(my_words_translator.send('dog'))
next(my_words_translator)
print(my_words_translator.send('cat'))
将打印 :
dog in other language
Unknown word...
概括如下:
使用send
生成器内的方法将数据发送回生成器。如果允许, a(yield)
使用。
yield
简直就像return
区别在于,下次你打电话给发电机时,从最后一次呼叫开始执行。yield
与返回不同的语句,当生成时, 堆叠框架不会被清理, 但是控件会被转回调用方, 所以下次调用函数时, 它的状态将会恢复 。
对于您的代码,函数get_child_candidates
动作就像一个循环器,这样当您扩展列表时,它会一次向新列表添加一个元素。
list.extend
在你公布的代码样本中, 只需将图普还给列表, 并附加到列表中, 就会更加清晰 。
收益率与返回相似。区别是:
收益率使函数可适用(在下个示例中)primes(n = 1)
函数成为可使用性) 。
它的基本意思是 函数下次被调用时, 它将继续从它离开的地方( 位于yield expression
).
def isprime(n):
if n == 1:
return False
for x in range(2, n):
if n % x == 0:
return False
else:
return True
def primes(n = 1):
while(True):
if isprime(n): yield n
n += 1
for n in primes():
if n > 100: break
print(n)
在上述例子中,如果isprime(n)
这是真的, 它会返回质号。 在下次迭代中, 它会从下一行继续
n += 1
从方案拟订的角度来看,迭代器是按下列方式执行的:Tunks 缩图.
实施迭代机、发电机和用于同时执行的线性集合,等等,作为杜丘,一种用途发送到关闭对象的信件它有一个调度员, 和给“ 消息” 的发件人解答.
"下一个"是发送到结束处的电文,该电文由“创建者”创建。亚列"打电话。
执行此计算有很多方法。 我使用突变, 但可以通过返回当前值和下一个生成者( 生成者) 返回当前值和下一个生成者( 生成者) 来进行这种不突变的计算( 生成者)优惠透明Racket使用一些中间语言对初始方案进行一系列转换,其中之一是进行这种改写,使产量经营者与较简单的经营者以某种语言进行转换。
这是如何重写产量的演示, 它使用 R6RS 的结构, 但语义与 Python 的相同 。 这是相同的计算模式, 只需要修改语法, 才能使用 Python 的 产量重写 。
Welcome to Racket v6.5.0.3.
-> (define gen
(lambda (l)
(define yield
(lambda ()
(if (null? l)
'END
(let ((v (car l)))
(set! l (cdr l))
v))))
(lambda(m)
(case m
('yield (yield))
('init (lambda (data)
(set! l data)
'OK))))))
-> (define stream (gen '(1 2 3)))
-> (stream 'yield)
1
-> (stream 'yield)
2
-> (stream 'yield)
3
-> (stream 'yield)
'END
-> ((stream 'init) '(a b))
'OK
-> (stream 'yield)
'a
-> (stream 'yield)
'b
-> (stream 'yield)
'END
-> (stream 'yield)
'END
->