Python 代码中的 yield 到底是什么?
在Python编程中,有一个强大而神秘的关键字,那就是yield。初学者常常被它搞得晕头转向,而高级开发者则借助它实现高效的代码。到底yield是什么?它又是如何在Python代码中发挥作用的呢?让我们一起来揭开它的面纱。
Python里的一个非常重要但也颇具迷惑性的关键词——yield。
什么是yield?为什么我们需要在Python中使用它?

来,让我们一起来拆解一下,看看yield到底是个啥。
迭代与可迭代对象
要搞明白yield,咱们先得弄清楚什么是可迭代对象(iterables)。
所谓可迭代对象,简单来说,就是你可以逐个读取其元素的对象,比如列表、字符串、文件等等。举个例子,当你创建一个列表时,你可以用for循环一个个地读取它的元素:
mylist = [1, 2, 3]
for i in mylist:
print(i)
输出会是:
1
2
3
这里的mylist就是一个可迭代对象。你还可以用列表推导式(list comprehension)来创建一个列表,它同样也是可迭代的:
mylist = [x*x for x in range(3)]
for i in mylist:
print(i)
输出是:
0
1
4
凡是你可以用for... in...来操作的东西,都是可迭代对象,包括列表、字符串、文件等等。
可迭代对象非常方便,因为你可以任意多次地读取它们的值,但前提是你得把所有值都存储在内存里。这就带来了一个问题:当数据量很大时,这种方式显然不太合适。
生成器
生成器(generators)是迭代器的一种,你只能遍历它们一次。生成器不像列表那样把所有的值都存储在内存里,而是即用即生成。来看看生成器的例子:
mygenerator = (x*x for x in range(3))
for i in mygenerator:
print(i)
输出和列表推导式一样:
0
1
4
但注意了,生成器只能使用一次,因为它们会“边用边忘”:计算0后忘记0,计算1后忘记1,最后计算4后结束。再用同一个生成器对象做for循环就没有结果了。

yield关键词
说到yield,这是个类似于return的关键词,但它返回的不是一个值,而是一个生成器。看看这个例子:
def create_generator():
mylist = range(3)
for i in mylist:
yield i*i
mygenerator = create_generator() # 创建一个生成器
print(mygenerator) # mygenerator 是一个生成器对象!
输出是:
<generator object create_generator at 0xb7555c34>
通过for循环遍历这个生成器:
for i in mygenerator:
print(i)
输出:
0
1
4
这个例子看起来简单,但它在处理大量数据时特别有用,因为生成器只在需要时生成值,而不是一次性生成所有值然后存储在内存中。
深入理解yield
为了彻底掌握yield,我们需要理解当调用生成器函数时,函数体内的代码并不会立即执行。函数返回的是一个生成器对象,然后你的代码会在每次调用for循环时从上次中断的地方继续执行,直到遇到下一个yield。
第一次调用for循环时,生成器对象会从头开始运行函数中的代码,直到遇到yield,然后返回循环中的第一个值。随后的每次调用都会执行函数中循环的下一次迭代,直到生成器不再有值返回。这可能是因为循环结束了,或者条件不再满足。
来看看一个实际的例子:
1 def _get_child_candidates(self, distance, min_dist, max_dist):
2 if self._leftchild and distance - max_dist < self._median:
3 yield self._leftchild
4 if self._rightchild and distance + max_dist >= self._median:
5 yield self._rightchild
这里的代码在每次使用生成器对象时都会被调用:
如果节点对象还有左子节点并且距离合适,返回下一个子节点。
如果节点对象还有右子节点并且距离合适,返回下一个子节点。
如果没有更多子节点,生成器会被认为是空的。
调用这个生成器的方法如下:
1 result, candidates = list(), [self]
2 while candidates:
3 node = candidates.pop()
4 distance = node._get_dist(obj)
5 if distance <= max_dist and distance >= min_dist:
6 result.extend(node._values)
7 candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))
8
9 return result
这里的代码有几个巧妙之处:
- 循环遍历一个列表,而列表在循环过程中会扩展。这样可以方便地遍历所有嵌套的数据,虽然有些危险,因为可能会陷入无限循环。在这个例子中,candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))用尽生成器的所有值,但while循环不断创建新的生成器对象,因为它们作用在不同的节点上会产生不同的值。
- extend()方法是列表对象的方法,它期望一个可迭代对象,并将其值添加到列表中。通常我们传递一个列表给它,但在代码中,它接收一个生成器,这是个好主意,因为:
- 你不需要读取值两次。
- 你可能有很多子节点,不想全部存储在内存中。
这段代码展示了Python为何如此酷:它不在乎方法的参数是列表还是其他可迭代对象。这种特性叫鸭子类型(duck typing),也是Python灵活性的一个体现。
高级用法
再来看一个更高级的用法——控制生成器的耗尽:
1 class Bank():
2 crisis = False
3 def create_atm(self):
4 while not self.crisis:
5 yield "$100"
6
7 hsbc = Bank()
8 corner_street_atm = hsbc.create_atm()
9 print(next(corner_street_atm)) # 输出 $100
10 print(next(corner_street_atm)) # 输出 $100
11 print([next(corner_street_atm) for _ in range(5)]) # 输出 ['$100', '$100', '$100', '$100', '$100']
12
13 hsbc.crisis = True
14 print(next(corner_street_atm)) # 输出 StopIteration
这里我们模拟了一个ATM机,在银行没有危机时,你可以不断取钱,但一旦危机来了,ATM机就会停止工作,即使是新的ATM机也不能再取钱了。
itertools模块
最后,给大家介绍一个非常有用的模块——itertools。这个模块包含了很多操作可迭代对象的特殊函数。如果你曾经希望复制一个生成器、连接两个生成器、用一行代码将值分组到嵌套列表中,或者在不创建另一个列表的情况下使用map和zip,那么就应该导入itertools。
举个例子,我们看看四匹马比赛的可能到达顺序:
import itertools horses = [1, 2, 3, 4]
races = itertools.permutations(horses)
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)]
itertools模块简直是Python程序员的好伙伴,可以让你在处理迭代对象时如虎添翼。
总结
yield是Python中一个强大的工具,它可以帮助你以一种高效的方式处理大量数据。理解yield的工作原理对于掌握Python编程至关重要。
在大数据时代,处理海量数据已成为常态。生成器作为一种高效的数据处理方式,因其优越的内存管理能力,受到了越来越多开发者的青睐。无论是日志处理、数据流分析,还是实时数据处理,生成器都展现了不可替代的价值。
通过对yield的详解,我们不仅理解了它的基本概念和用法,还认识到它在高效数据处理中的重要性。掌握yield,将为你的Python编程之旅增添一把利器。

Python 代码中的 yield 到底是什么?的更多相关文章
- Kivy A to Z -- 怎样从python代码中直接訪问Android的Service
在Kivy中,通过pyjnius扩展能够间接调用Java代码,而pyjnius利用的是Java的反射机制.可是在Python对象和Java对象中转来转去总让人感觉到十分别扭.好在android提供了b ...
- Python类中的self到底是干啥的
Python类中的self到底是干啥的 Python编写类的时候,每个函数参数第一个参数都是self,一开始我不管它到底是干嘛的,只知道必须要写上.后来对Python渐渐熟悉了一点,再回头看self的 ...
- pycharm运行Pytest,有没有将Pytest写入Python代码中的区别
初学pytest. 将pytest写进Python代码中 不同运行方式都可正常运行 =======================**********************========= ...
- python代码中判断版本
在python代码中判断python版本: if sys.version_info < (3, 0): lib.make_flows.argtypes = [c_char_p, c_char_p ...
- 如何在创建hive表格的python代码中导入外部文件
业务场景大概是这样的,我要对用户博文进行分词(这个步骤可以看这篇文章如何在hive调用python的时候使用第三方不存在的库-how to use external python library in ...
- python代码中pass的用法
我们有时会在方法中写一些注释代码,用来提示这个方法是干嘛的之类,看下面代码: class Game_object: def __init__(self, name): self.name = name ...
- 解决python代码中含有中文报错
python中写入中文时报错如下图所示: 依照网上解决方法:在py文件中加入:#encoding=utf-8 然后继续报错如下图所示: 解决方法: 在py文件中加入: import sysreload ...
- Python代码中func(*args, **kwargs)
这是Python函数可变参数 args及kwargs *args表示任何多个无名参数,它是一个tuple **kwargs表示关键字参数,它是一个dict 测试代码如下: def foo(*args, ...
- Python面向对象中的self到底是什么?
初次接触类的概念,在学习的网页上,对self的解释是self是方法的一个参数,在方法调用的时候,这个参数是默认传参数的我们看一个例子 很多人学习python,不知道从何学起.很多人学习python,掌 ...
- python代码中碰到的问题及解决
一.针对raw_input输入的字符进行类型判断及转换: raw_input输入默认为字符,如果输入的是数字字符,想自动转换,即:输入为a,不做操作,如果输入为3,即转化为整数. 可利用try..ex ...
随机推荐
- 申请并部署免费的 SSL/TLS 证书
对于囊中羞涩的我们来说,只要能白嫖,就绝不乱花钱.惯常申请免费 SSL/TLS 证书的途径有: 各大云服务平台限量提供.比如阿里云会给每个账号每年 20 个证书的申请额度.缺点是不支持泛域名,一年后须 ...
- 调试YOLOv3/YOLOv5过程中遇到的问题汇总
今日立冬 yolov1 yolo1论文 https://www.bilibili.com/video/BV15w411Z7LG yolo2论文 https://www.bilibili.com/vid ...
- js 留言板(带删除功能)
本文所用的知识点:创建节点和添加节点 创建节点:document.createElement('li') 添加节点 node(父亲节点).appendChild(child) child:子节 ...
- 初识c语言—c语言的初步认识和一个简单的程序
C语言是什么 编程语言(编程语言是控制计算机的一系列指令,他又固定的格式和词汇.同时也叫计算机语言(计算机语言是,人和计算机通讯的语言)) C语言的特点 语言简洁,紧凑,使用方便 运算符丰富 数据类型 ...
- 剑指Offer-54.字符流中第一个不重复的字符(C++/Java)
题目: 请实现一个函数用来找出字符流中第一个只出现一次的字符.例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g".当从该字符流中读出前 ...
- kettle从入门到精通 第五十六课 ETL之kettle Microsoft Excel Output
1.9.4 版本的kettle中有两个Excel输出,Excel输出和Microsoft Excel输出.前者只支持xls格式,后者支持xls和xlsx两种格式,本节课主要讲解步骤Microsoft ...
- P9174
problem & blog 子任务 \(1\) 和子任务 \(2\) 都比较好做.所以我们这里不讲. 状态将是数字 \(n\) (每个颜色的频率的排序数组)的所有分区,因为当我们旋转每种颜色 ...
- 开源高性能结构化日志模块NanoLog
最近在写数据库程序,需要一个高性能的结构化日志记录组件,简单研究了一下Microsoft.Extensions.Logging和Serilog,还是决定重造一个轮子. 一.使用方法 直接参考以 ...
- Scrapy框架(二)--持久化存储
持久化存储 scrapy的高性能持久化存储操作,有两种方式:基于终端指令的持久化存储 和 基于管道的持久化存储操作. 基于终端指令的持久化存储 保证爬虫文件的parse方法中有可迭代类型对象(通常为列 ...
- disabled 和 readonly 都是 HTML 表单元素的属性,它们有一些相同点和不同点。
disabled 和 readonly 都是 HTML 表单元素的属性,它们有一些相同点和不同点. 相同点: disabled 和 readonly 属性都可以用于表单中的输入框.文本域等元素,用于控 ...