Python中`yield`关键字详解
Python中`yield`关键字有什么用?
yield
关键字有什么用? 它能做什么?例如,我试图理解这段代码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
回答
要了解yield的作用,您必须了解生成器是什么。 在了解生成器之前,您必须了解iterables。
迭代器
创建列表时,您可以逐个读取其项目。 逐个读取其项称为迭代:
mylist = [1, 2, 3]
for i in mylist:
... print(i)
1
2
3
mylist是一个可迭代的。 当您使用列表理解时,您创建了一个列表,因此一个可迭代的:
mylist = [x*x for x in range(3)]
for i in mylist:
... print(i)
0
1
4
您可以使用"for... in..."的所有内容都是可迭代的;lists,strings,文件。..
这些iterables很方便,因为您可以随心所欲地读取它们,但是您将所有值存储在内存中,当您有很多值时,这并不总是您想要的。
发电机
生成器是迭代器,一种可迭代的你只能迭代一次。 生成器不会将所有值存储在内存中,它们会动态生成值:
mygenerator = (x*x for x in range(3))
for i in mygenerator:
... print(i)
0
1
4
除了你使用()而不是[]之外,它是一样的。 但是,您不能第二次执行for i in mygenerator,因为生成器只能使用一次:它们计算0,然后忘记它并计算1,并结束计算4,一个接一个。
产量
yield是一个像return一样使用的关键字,除了函数将返回一个生成器。
def create_generator():
... mylist = range(3)
... for i in mylist:
... yield i*i
...
mygenerator = create_generator() # create a generator
print(mygenerator) # mygenerator is an object!
<generator object create_generator at 0xb7555c34>
for i in mygenerator:
... print(i)
0
1
4
这里是一个无用的例子,但是当你知道你的函数将返回一组巨大的值时,它很方便,你只需要读取一次。
要掌握yield,您必须了解当您调用函数时,您在函数体中编写的代码不会运行。函数只返回生成器对象,这有点棘手。
然后,您的代码将从每次for使用生成器时停止的位置继续。
现在最难的部分:
当for第一次调用从你的函数创建的生成器对象时,它将从一开始就在你的函数中运行代码,直到它点击yield,然后它将返回循环的第一个值。 然后,每个后续调用都将运行您在函数中编写的循环的另一个迭代,并返回下一个值。 这将继续下去,直到生成器被认为是空的,这发生在函数运行而没有击中yield时。 这可能是因为循环已经结束,或者因为你不再满足an"if/else"。
你的代码解释
发生器:
Here you create the method of the node object that will return the generator
def _get_child_candidates(self, distance, min_dist, max_dist):
# Here is the code that will be called each time you use the generator object:
# If there is still a child of the node object on its left
# AND if the distance is ok, return the next child
if self._leftchild and distance - max_dist < self._median:
yield self._leftchild
# If there is still a child of the node object on its right
# AND if the distance is ok, return the next child
if self._rightchild and distance + max_dist >= self._median:
yield self._rightchild
# If the function arrives here, the generator will be considered empty
# there is no more than two values: the left and the right children
调用者:
Create an empty list and a list with the current object reference
result, candidates = list(), [self]
Loop on candidates (they contain only one element at the beginning)
while candidates:
# Get the last candidate and remove it from the list
node = candidates.pop()
# Get the distance between obj and the candidate
distance = node._get_dist(obj)
# If distance is ok, then you can fill the result
if distance <= max_dist and distance >= min_dist:
result.extend(node._values)
# Add the children of the candidate in the candidate's list
# so the loop will keep running until it will have looked
# at all the children of the children of the children, etc. of the candidate
candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))
return result
此代码包含几个智能部分:
循环在列表上迭代,但在循环迭代时列表会扩展。 这是一种简洁的方式来遍历所有这些嵌套数据,即使它有点危险,因为你最终可能会有一个无限循环。 在这种情况下,candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))耗尽了生成器的所有值,但是while不断创建新的生成器对象,这些对象将产生与以前的值不同的值,因为它不在同一个节点上应用。
extend()方法是一个列表对象方法,它期望一个可迭代的,并将其值添加到列表中。
通常我们会传递一个列表给它:
a = [1, 2]
b = [3, 4]
a.extend(b)
print(a)
[1, 2, 3, 4]
但是在你的代码中,它得到了一个生成器,这很好,因为:
您不需要读取两次值。
你可能有很多孩子,你不希望他们都存储在内存中。
它的工作原理是因为Python不关心方法的参数是否是列表。 Python需要迭代器,因此它将与字符串、列表、元组和生成器一起工作! 这被称为duck typing,也是Python如此酷的原因之一。 但这是另一个故事,另一个问题。..
你可以在这里停下来,或者读一点,看看生成器的高级使用:
控制发电机耗尽
class Bank(): # Let's create a bank, building ATMs
... crisis = False
... def create_atm(self):
... while not self.crisis:
... yield "100
print(corner_street_atm.next())100', '
100', '
100']
hsbc.crisis = True # Crisis is coming, no more money!
print(corner_street_atm.next())
<type 'exceptions.StopIteration'>
wall_street_atm = hsbc.create_atm() # It's even true for new ATMs
print(wall_street_atm.next())
<type 'exceptions.StopIteration'>
hsbc.crisis = False # The trouble is, even post-crisis the ATM remains empty
print(corner_street_atm.next())
<type 'exceptions.StopIteration'>
brand_new_atm = hsbc.create_atm() # Build a new one to get back in business
for cash in brand_new_atm:
... print cash100
100
100
a = [1, 2]
>>> b = [3, 4]
>>> a.extend(b)
>>> print(a)
[1, 2, 3, 4]
但是在你的代码中,它得到了一个生成器,这很好,因为:
您不需要读取两次值。
你可能有很多孩子,你不希望他们都存储在内存中。
它的工作原理是因为Python不关心方法的参数是否是列表。 Python需要迭代器,因此它将与字符串、列表、元组和生成器一起工作! 这被称为duck typing,也是Python如此酷的原因之一。 但这是另一个故事,另一个问题。..
你可以在这里停下来,或者读一点,看看生成器的高级使用:
控制发电机耗尽
>>> class Bank(): # Let's create a bank, building ATMs
... crisis = False
... def create_atm(self):
... while not self.crisis:
... yield "100
>>> print(corner_street_atm.next())100', '
100', '
100']
>>> hsbc.crisis = True # Crisis is coming, no more money!
>>> print(corner_street_atm.next())
<type 'exceptions.StopIteration'>
>>> wall_street_atm = hsbc.create_atm() # It's even true for new ATMs
>>> print(wall_street_atm.next())
<type 'exceptions.StopIteration'>
>>> hsbc.crisis = False # The trouble is, even post-crisis the ATM remains empty
>>> print(corner_street_atm.next())
<type 'exceptions.StopIteration'>
>>> brand_new_atm = hsbc.create_atm() # Build a new one to get back in business
>>> for cash in brand_new_atm:
... print cash100
100
100
100
100"
>>> hsbc = Bank() # When everything's ok the ATM gives you as much as you want
>>> corner_street_atm = hsbc.create_atm()
>>> print(corner_street_atm.next())100
>>> print([corner_street_atm.next() for cash in range(5)])
['100', '
100', '
100
100
100
100
100
...
注意:对于Python3,使用print(corner_street_atm.next())或print(next(corner_street_atm))
它对于控制对资源的访问等各种事情都很有用。
Itertools,你最好的朋友
itertools模块包含用于操作iterables的特殊函数。 曾经想复制一个发电机吗? 链两个发电机? 在一个单行嵌套列表中分组值? Map / Zip不创建另一个列表?
那么就import itertools。
一个例子? 让我们来看看四匹马比赛的可能到达顺序:
horses = [1, 2, 3, 4]
races = itertools.permutations(horses)
print(races)
<itertools.permutations object at 0xb754f1dc>
print(list(itertools.permutations(horses)))
hsbc = Bank() # When everything's ok the ATM gives you as much as you want
>>> corner_street_atm = hsbc.create_atm()
>>> print(corner_street_atm.next())100
>>> print([corner_street_atm.next() for cash in range(5)])
['100', '
100', '
100
100
100
100
100
...
注意:对于Python3,使用print(corner_street_atm.next())或print(next(corner_street_atm))
它对于控制对资源的访问等各种事情都很有用。
Itertools,你最好的朋友
itertools模块包含用于操作iterables的特殊函数。 曾经想复制一个发电机吗? 链两个发电机? 在一个单行嵌套列表中分组值? Map / Zip不创建另一个列表?
那么就import itertools。
一个例子? 让我们来看看四匹马比赛的可能到达顺序:
>>> horses = [1, 2, 3, 4]
>>> races = itertools.permutations(horses)
>>> print(races)
<itertools.permutations object at 0xb754f1dc>
>>> print(list(itertools.permutations(horses)))
[(1, 2, 3, 4),
(1, 2, 4, 3),
(1, 3, 2, 4),
(1, 3, 4, 2),
(1, 4, 2, 3),
(1, 4, 3, 2),
(2, 1, 3, 4),
(2, 1, 4, 3),
print(corner_street_atm.next())100
>>> print([corner_street_atm.next() for cash in range(5)])
['100', '
100', '
100
100
100
100
100
...
注意:对于Python3,使用print(corner_street_atm.next())或print(next(corner_street_atm))
它对于控制对资源的访问等各种事情都很有用。
Itertools,你最好的朋友
itertools模块包含用于操作iterables的特殊函数。 曾经想复制一个发电机吗? 链两个发电机? 在一个单行嵌套列表中分组值? Map / Zip不创建另一个列表?
那么就import itertools。
一个例子? 让我们来看看四匹马比赛的可能到达顺序:
>>> horses = [1, 2, 3, 4]
>>> races = itertools.permutations(horses)
>>> print(races)
<itertools.permutations object at 0xb754f1dc>
>>> print(list(itertools.permutations(horses)))
[(1, 2, 3, 4),
(1, 2, 4, 3),
(1, 3, 2, 4),
(1, 3, 4, 2),
(1, 4, 2, 3),
(1, 4, 3, 2),
(2, 1, 3, 4),
(2, 1, 4, 3),
(2, 3, 1, 4),
(2, 3, 4, 1),
(2, 4, 1, 3),
(2, 4, 3, 1),
(3, 1, 2, 4),
(3, 1, 4, 2),
(3, 2, 1, 4),
(3, 2, 4, 1),
(3, 4, 1, 2),
(3, 4, 2, 1),
(4, 1, 2, 3),
(4, 1, 3, 2),
(4, 2, 1, 3),
(4, 2, 3, 1),
(4, 3, 1, 2),
(4, 3, 2, 1)]
print(corner_street_atm.next())
<type 'exceptions.StopIteration'>
>>> wall_street_atm = hsbc.create_atm() # It's even true for new ATMs
>>> print(wall_street_atm.next())
<type 'exceptions.StopIteration'>
>>> hsbc.crisis = False # The trouble is, even post-crisis the ATM remains empty
>>> print(corner_street_atm.next())
<type 'exceptions.StopIteration'>
>>> brand_new_atm = hsbc.create_atm() # Build a new one to get back in business
>>> for cash in brand_new_atm:
... print cash100
100
100
100
$100
...
注意:对于Python3,使用print(corner_street_atm.next())或print(next(corner_street_atm))
它对于控制对资源的访问等各种事情都很有用。
Itertools,你最好的朋友
itertools模块包含用于操作iterables的特殊函数。 曾经想复制一个发电机吗? 链两个发电机? 在一个单行嵌套列表中分组值? Map / Zip不创建另一个列表?
那么就import itertools。
一个例子? 让我们来看看四匹马比赛的可能到达顺序:
>>> horses = [1, 2, 3, 4]
>>> races = itertools.permutations(horses)
>>> print(races)
<itertools.permutations object at 0xb754f1dc>
>>> print(list(itertools.permutations(horses)))
[(1, 2, 3, 4),
(1, 2, 4, 3),
(1, 3, 2, 4),
(1, 3, 4, 2),
(1, 4, 2, 3),
(1, 4, 3, 2),
(2, 1, 3, 4),
(2, 1, 4, 3),
(2, 3, 1, 4),
(2, 3, 4, 1),
(2, 4, 1, 3),
(2, 4, 3, 1),
(3, 1, 2, 4),
(3, 1, 4, 2),
(3, 2, 1, 4),
(3, 2, 4, 1),
(3, 4, 1, 2),
(3, 4, 2, 1),
(4, 1, 2, 3),
(4, 1, 3, 2),
(4, 2, 1, 3),
(4, 2, 3, 1),
(4, 3, 1, 2),
(4, 3, 2, 1)]
理解迭代的内在机制
迭代是一个隐含iterables(实现iter()方法)和iterators(实现next()方法)的过程。 Iterables是您可以从中获取迭代器的任何对象。 迭代器是允许您迭代可迭代对象的对象。
Python中`yield`关键字详解的更多相关文章
- 【转载】C/C++中extern关键字详解
1 基本解释:extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义.此外extern也可用来进行链接指定. 也就是说extern ...
- python中threading模块详解(一)
python中threading模块详解(一) 来源 http://blog.chinaunix.net/uid-27571599-id-3484048.html threading提供了一个比thr ...
- Python中time模块详解
Python中time模块详解 在平常的代码中,我们常常需要与时间打交道.在Python中,与时间处理有关的模块就包括:time,datetime以及calendar.这篇文章,主要讲解time模块. ...
- 第7.19节 Python中的抽象类详解:abstractmethod、abc与真实子类
第7.19节 Python中的抽象类详解:abstractmethod.abc与真实子类 一. 引言 前面相关的章节已经介绍过,Python中定义某种类型是以实现了该类型对应的协议为标准的,而不 ...
- yield关键字详解与三种用法
本篇文章比较硬核, 适合有一定Python基础的读者阅读, 如果您对Python还不甚了解可以先关注我哦, 我会持续更新Python技术文章 yield详解 yield与return相同每次调用都会返 ...
- JS中this关键字详解
本文主要解释在JS里面this关键字的指向问题(在浏览器环境下). 阅读此文章,还需要心平气和的阅读完,相信一定会有所收获,我也会不定期的发布,分享一些文章,共同学习 首先,必须搞清楚在JS里面,函数 ...
- JS 中 this 关键字详解
本文主要解释在JS里面this关键字的指向问题(在浏览器环境下). 首先,必须搞清楚在JS里面,函数的几种调用方式: 普通函数调用 作为方法来调用 作为构造函数来调用 使用apply/call方法来调 ...
- python中常用模块详解二
log模块的讲解 Python 使用logging模块记录日志涉及四个主要类,使用官方文档中的概括最为合适: logger提供了应用程序可以直接使用的接口API: handler将(logger创建的 ...
- 76.Python中F表达式详解
F表达式是用来优化ORM操作数据库的. 举个例子:我们做口罩的公司要将所有员工的薪水增加2000元,如果按照正常的流程,应该是先从数据库中提取所有的员工的工资到Python内存中,然后使用Python ...
- python 中的unicode详解
通过例子来看问题是比较容易懂的. 首先来看,下面这个是我新建的一个txt文件,名字叫做ivan_utf8.txt,然后里面随便编辑了一些东西. 然后来用控制台打开这个文件,同样也是截图: 这里就是简单 ...
随机推荐
- 基于python的视频点播网站(python+django+vue开发的视频点播网站-视频管理系统)
演示地址 前台地址: http://video.gitapp.cn 后台地址:http://video.gitapp.cn/admin 后台管理帐号: 用户名:admin123 密码:admin123 ...
- DBA实战面试题(一)
数据库面试测试题(一) 简述当前主流RDBMS软件有哪些?开源且跨平台的数据库软件有哪些? 参考答案 当前主流的数据库服务器软件有: Oracle . DB2 . SQL SERVER .MySQL ...
- Error adding module to project: null I(IDEA创建maven项目时遇到此提示)
1.问题 在已创建一个springboot项目的时候,想要再增添一个Maven项目,发生报错 2.解决 根本原因是创建maven模块时选择的sdk版本过高(选用了openjdk19).选用jdk1.8 ...
- 问题--如何快速复制Typora(Markdown)中的代码块/区块等
使用快捷键ctrl+E,选中相同格式的文字,然后快速复制即可
- C++中vector容器详解
参考链接:https://www.runoob.com/w3cnote/cpp-vector-container-analysis.html 一.什么是vector? 向量(Vector)是一个封装了 ...
- 【canvas】 绘制七巧板
效果图: 代码 : <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...
- [转帖]SecurityProtocolType 枚举
https://learn.microsoft.com/zh-cn/dotnet/api/system.net.securityprotocoltype?view=net-8.0 命名空间: Syst ...
- [转帖]Linux系统下cpio命令详解
简介 cpio主要是解压或者将文件压缩到指定文件中即copy-in和copy-out模式. 参数说明 参数 参数说明 -i copy-in模式,解压文件 -o copy-out模式,即压缩文件 -d ...
- [转帖]GCC 编译及编译选项
俗话说:'工欲善其事,必先利其器',一直在工作中使用GNU C编译器(以下简称GCC),这里对GCC的一些警告选项细致的分析,并列举几个简单的例子[注1]供分析参考. 1. -Wall集合警告选项我们 ...
- [转帖]Red Hat Enterprise Linux 8 和 9 中可用的 IO 调度程序
Red Hat 弃用了 Red Hat Enterprise Linux 7 中可用的 I/O 调度程序,并引入了四个新的 I/O 调度程序,如下所示, 运行以下命令检查 RHEL8 和 RHEL9 ...