[翻译]Python中yield的解释
问题:
Python中yield关键字的作用是什么?它做了什么?
例如,我想理解以下代码
def node._get_child_candidates(self, distance, min_dist, max_dist):if self._leftchild and distance - max_dist < self._median:yield self._leftchildif self._rightchild and distance + max_dist >= self._median:yield self._rightchild
下面是调用者
result, candidates = list(), [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这个函数被调用时发生了什么?返回了一个列表?还是只返回了一个元素?然后又再次被调用?什么时候调用结束?
这段代码的来源 Jochen Schulz (jrschulz), who made a great Python library for metric spaces. 完整源码链接: here
要了解yield的作用,你必须先明白什么是生成器,在此之前,你需要了解什么是可迭代对象(可迭代序列)
迭代
你可以创建一个列表,然后逐一遍历,这就是迭代
>>> 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…” 处理的都是可迭代对象:列表,字符串,文件…. 这些迭代对象非常便捷,因为你可以尽可能多地获取你想要的东西
但,当你有大量数据并把所有值放到内存时,这种处理方式可能不总是你想要的 (but you store all the values in memory and it’s not always what you want when you have a lot of values.)
生成器
生成器是迭代器,但你只能遍历它一次(iterate over them once) 因为生成器并没有将所有值放入内存中,而是实时地生成这些值
>>> 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
yield是一个关键词,类似return, 不同之处在于,yield返回的是一个生成器
>>> def createGenerator():
... mylist = range(3)
... for i in mylist:
... yield i*i
...
>>> mygenerator = createGenerator() # create a generator
>>> print(mygenerator) # mygenerator is an object!
<generator object createGenerator at 0xb7555c34>
>>> for i in mygenerator:
... print(i)
0
1
4
这个例子并没有什么实际作用,仅说明当你知道你的函数将产生大量仅被读取一次的数据时,使用生成器将是十分有效的做法
要掌握yield,你必须明白 - 当你调用这个函数,函数中你书写的代码并没有执行。这个函数仅仅返回一个生成器对象
这有些狡猾 :-)
然后,在每次for循环使用生成器时,都会执行你的代码
然后,是比较困难的部分:
第一次函数将会从头运行,直到遇到yield,然后将返回循环的首个值. 然后,每次调用,都会执行函数中的循环一次,返回下一个值,直到没有值可以返回
当循环结束,或者不满足”if/else”条件,导致函数运行但不命中yield关键字,此时生成器被认为是空的
问题代码的解释
生成器:
# 这你你创建了node的能返回生成器的函数
def node._get_child_candidates(self, distance, min_dist, max_dist):# 这里的代码你每次使用生成器对象都会调用# 如果node节点存在左子节点,且距离没问题,返回该节点
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 = list(), [self]# 当前候选非空,循环(开始时仅有一个元素)
while candidates:# 从候选列表取出最后一个元素作为当前节点node = candidates.pop()# 获取obj和当前节点距离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))# 注意这里extend会反复调用获取到所有生成器返回值return result
这段代码包含几个灵活的部分:
1.这个循环遍读取历候选列表,但过程中,候选列表不断扩展:-)
这是一种遍历嵌套数据的简明方法,虽然有些危险,你或许会陷入死循环中
在这个例子中, candidates.extend(node._get_child_candidates(distance, min_dist, max_dist)) 读取了生成器产生的所有值, 同时while循环产生新的生成器对象加入到列表,因为每个对象作用在不同节点上,所以每个生成器都将生成不同的值
2.列表方法extend() 接收一个生成器,生成器的所有值被添加到列表中
通常,我们传一个列表作为参数:
>>> a = [1, 2]
>>> b = [3, 4]
>>> a.extend(b)
>>> print(a)
[1, 2, 3, 4]
但是,在代码中,这个函数接受到一个生成器
这样的做法好处是:
1.你不需要重复读这些值
2.你可能有海量的子节点,但是不希望将所有节点放入内存
并且,可以这么传递生成器作为参数的原因是,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"
>>> 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())
$100
>>> print([corner_street_atm.next() for cash in range(5)])
['$100', '$100', '$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 # 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 cash
$100
$100
$100
$100
$100
$100
$100
$100
$100
...
这在很多场景都非常有用,例如控制资源的获取
Itertools
一个很好的工具
itertools模块包含很多处理可迭代对象的具体方法. 例如
复制一个生成器?连接两个生成器?一行将嵌套列表中值分组?不使用另一个列表进行Map/Zip? (Ever wish to duplicate a generator? Chain two generators? Group values in a nested list with a one liner? Map / Zip without creating another list?)
只需要使用itertools模块
一个例子,4匹马赛跑的可能抵达顺序
>>> 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)]
了解迭代器的内部机制
迭代过程包含可迭代对象(实现iter()方法) 和迭代器(实现next()方法)
你可以获取一个迭代器的任何对象都是可迭代对象,迭代器可以让你迭代遍历一个可迭代对象(Iterators are objects that let you iterate on iterables.) [好拗口:]
更多关于这个问题的 how does the for loop work
如果你喜欢这个回答,你也许会喜欢我关于 decorators 和 metaclasses 的解释
[翻译]Python中yield的解释相关推荐
- python中yield的用法(生成器的讲解)
2 理解说明yield与生成器 在Python中,使用yield的函数被称为生成器函数(generator function). 生成器有两种方法:next()和send(),都可以调用生成器 yie ...
- Python中yield和yield from的用法
yield 后面接的是 future 对象 调用方 委托生成器 yield from 直接给出循环后的结果 yield from 委托者和子生成器直接通信 yield from 直接处理stopIte ...
- Python中yield简单用法
Python中yield简单用法 你或许知道带有yield的函数在Python中被称之为generator,那何为 generator? 我们暂时抛开generator,先从一个常见编程题目开始,循序 ...
- python 中 yield 的使用
python中yield在函数中的使用 正是因为函数含有这个yield,所以,该函数不再是普通的函数,而是生成器函数(generator function).下面通过小例子来说明一下这个内置函数的特性 ...
- 深入理解Python中的全局解释锁GIL
深入理解Python中的全局解释锁GIL 转自:https://zhuanlan.zhihu.com/p/75780308 注:本文为蜗牛学院资深讲师卿淳俊老师原创,首发自公众号https://mp. ...
- python的yield是什么意思,python生成器是怎么使用的 python中yield是什么意思
python中return和yield怎么用的?两个有什么区别?你从未驯服过她,她只是在爱你的时候收起獠牙. yield yield是用于生成器.什么是生成器,你可以通俗的认为,在一个函数中,使用了y ...
- python中yield语句的作用_Python中关键字yield有什么作用
python中,yield关键字的作用:1.将一个函数修改为生成器,利用生成器可以有效地节约系统资源,避免不必要的内存占用:2.用于定义上下文管理器:3.协程:4.配合from形成yield from ...
- python yield理解_对Python中Yield的理解
看到下面这段程序的时候,有点不明白这个yield到底是个啥东西,看了网上很多的博客,大致理解了yield的含义,所以记录下来. 要说yield首先要说python中的生成器,那么什么是生成器? 假设有 ...
- python中yield使用
16.yield使用 列表推导与生成器表达式 当我们创建了一个列表的时候,就创建了一个可以迭代的对象: >>> squares=[n*n for n in range(3)] > ...
最新文章
- hdu 1814 字典序最小的2sat(暴力深搜)
- gzcms技术开发文档
- 从“鞭打快牛”故事来看团队的领导力
- shell的logo含义_Shell(壳牌石油)标志历史
- 建立企业内部maven服务器并使用Android Studio发布公共项目
- ASP.NET- 执行SQL超时的解决方案
- html在新网页输出结果是,JavaScript考试试卷
- iOS非越狱自动化脚本的方案
- spring-quartz表达式介绍
- windows 系统 system 进程占用80端口
- 2021.09.17 word文档撤销按钮变灰,快捷键失效解决办法
- 停车位检测方法研究综述
- 微软的一道前端面试题
- 【PE】PE文件结构学习
- [PHP] B2B2C商品模块数据库设计
- 有感于技术出身的创业若干思考
- 中国医药外包市场发展前景预测与竞争态势分析报告2022-2028年版
- 数字化转型背景下的测试转型
- POI java excel 生成下拉列表
- 黑马程序员_配置环境变量
热门文章
- 2021-2027年中国涂装行业市场需求预测与投资战略规划分析报告
- perl: warning: Setting locale failed. Falling back to a fallback locale (“en_HK.UTF-8“).
- 机器翻译评测——BLEU算法详解 (新增 在线计算BLEU分值)评估
- 笔记本电脑的有线和无线网络同时使用,如何设置?
- Yolov3网络架构分析
- 激光雷达数据到云cloud
- 2021年大数据Hadoop(三):Hadoop国内外应用
- 2021年大数据ZooKeeper(三):Zookeeper数据模型和节点类型
- 2021年大数据Spark(二十八):SparkSQL案例三电影评分数据分析
- 【杂】LaTeX中一些符号的输入方法