何为使用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 空间.
下面是浅白语言的例子。我将提供高层次人类概念与低层次Python概念之间的对应关系。
我想用数字序列操作, 但我不想用这个序列的创建来烦恼我自己, 我只想专注于我想做的操作。 因此, 我做以下工作:
- 我打电话给你,告诉你,我想要一个数字序列 以特定的方式计算, 我让你知道算法是什么。
此步骤对应于def
内插入发电机函数,即包含yield
.
- 稍后,我告诉你, "好了,准备好告诉我数字的顺序"。
此步骤对应于调用发电机函数, 以返回发电机对象 。注意不要告诉我任何数字 你只要拿起你的纸和铅笔
- 我问你,"告诉我下一个号码",然后你告诉我第一个号码, 在那之后,你等我问你下一个号码。你的工作是记住你在哪里,你已经说过什么号码,下一个号码是什么。 我不在乎细节。
此步骤对应于调用next(generator)
在发电机的物体上。
(在Python 2,.next
是产生器物体的一种方法;在Python 3中,它被命名为.__next__
,但正确的称呼方式是使用内置next()
函数类似len()
和.__len__
)
- ...重复前一步,直到...
- 最终,你可能会走到尽头。你不会告诉我一个数字;你只会喊叫,“抓住你的马!我受够了!不再有数字了!”
此步骤对应于生成器对象结束工作, 并提升StopIteration
例外。
生成器函数不需要提出例外。 当函数结束或发布时自动生成 。return
.
这就是发电机(包含yield
;它开始执行第一个next()
时暂停yield
,当要求next()
它从最后一点继续值 。 它的设计完全符合 Python 的迭代协议, 它描述了如何按顺序请求值 。
循环程序最著名的用户是for
在 Python 中命令。 所以, 当您做 :
for item in sequence:
这不重要,如果sequence
是列表、字符串、字典或生成器对象对象如上文所述;结果相同:您逐个阅读顺序中的项目。
请注意def
函数内含有yield
关键字不是创建生成器的唯一方法; 它只是创建生成器的最简单的方法 。
将 " 更准确的信息 " 改为 " 更准确的信息 "迭代器类型、、 和收益单报表和发电机发电机在 Python 文档中。
简单解答
函数至少包含一个时yield
语句,函数自动成为发电机功能。当您调用发电机功能时, python 在发电机功能中执行代码,直到yield
发生声明。yield
当您再次调用发电机功能时, python 继续从冻结位置执行发电机功能中的代码,直到yield
发电机函数执行代码直到发电机功能用完时没有yield
语句。
基准基准基准基准基准基准基准
创建列表并返回它 :
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
摘要摘要摘要
生成器函数需要稍多一点时间来执行, 而不是返回列表但少用内存的函数 。
下面是浅白语言的例子。我将提供高层次人类概念与低层次Python概念之间的对应关系。
我想用数字序列操作, 但我不想用这个序列的创建来烦恼我自己, 我只想专注于我想做的操作。 因此, 我做以下工作:
- 我打电话给你,告诉你,我想要一个数字序列 以特定的方式计算, 我让你知道算法是什么。
此步骤对应于def
内插入发电机函数,即包含yield
.
- 稍后,我告诉你, "好了,准备好告诉我数字的顺序"。
此步骤对应于调用发电机函数, 以返回发电机对象 。注意不要告诉我任何数字 你只要拿起你的纸和铅笔
- 我问你,"告诉我下一个号码",然后你告诉我第一个号码, 在那之后,你等我问你下一个号码。你的工作是记住你在哪里,你已经说过什么号码,下一个号码是什么。 我不在乎细节。
此步骤对应于调用next(generator)
在发电机的物体上。
(在Python 2,.next
是产生器物体的一种方法;在Python 3中,它被命名为.__next__
,但正确的称呼方式是使用内置next()
函数类似len()
和.__len__
)
- ...重复前一步,直到...
- 最终,你可能会走到尽头。你不会告诉我一个数字;你只会喊叫,“抓住你的马!我受够了!不再有数字了!”
此步骤对应于生成器对象结束工作, 并提升StopIteration
例外。
生成器函数不需要提出例外。 当函数结束或发布时自动生成 。return
.
这就是发电机(包含yield
;它开始执行第一个next()
时暂停yield
,当要求next()
它从最后一点继续值 。 它的设计完全符合 Python 的迭代协议, 它描述了如何按顺序请求值 。
循环程序最著名的用户是for
在 Python 中命令。 所以, 当您做 :
for item in sequence:
这不重要,如果sequence
是列表、字符串、字典或生成器对象对象如上文所述;结果相同:您逐个阅读顺序中的项目。
请注意def
函数内含有yield
关键字不是创建生成器的唯一方法; 它只是创建生成器的最简单的方法 。
将 " 更准确的信息 " 改为 " 更准确的信息 "迭代器类型、、 和收益单报表和发电机发电机在 Python 文档中。
缩略yield
Python 中的关键字用于退出代码而不干扰本地变量状态,当函数再次被称为“执行”时,从我们离开代码的最后一点开始。
以下示例说明yield
:
def counter():
x=2
while x < 5:
yield x
x += 1
print("Initial value of x: ", counter())
for y in counter():
print(y)
上述代码产生以下输出:
Initial value of x: <generator object counter at 0x7f0263020ac0>
2
3
4
简单使用实例 :
>>> def foo():
yield 100
yield 20
yield 3
>>> for i in foo(): print(i)
100
20
3
>>>
如何运行 : 调用时, 函数会立即返回对象。 对象可以传递到下一个( ) 函数 。 当调用下一个( ) 函数时, 您的函数会一直运行到下一个产值, 并为下一个( ) 函数提供返回值 。
在引擎盖下, 循环确认对象是一个生成对象, 并使用下一个( ) 来获取下一个值 。
在一些语言中,比如ES6和更高语言中,它的实施略有不同, 所以下一个是生成对象的成员函数, 每次它得到下一个值时, 你就可以从调用器中传递数值。 所以如果结果是生成器, 那么你可以做类似y=结果。 ext( 555) , 而程序生成值可以说像 z = 产值 999 。 y 的值将是 999 , 下一个产值是 999, 而 z 的值将是 555 , 下一个产值是 555。 Python 获取并发送方法也有类似的效果 。
也可以将数据发送回生成器!
事实上,正如这里许多答案所解释的,使用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)
使用。