生成器 yield
由于生成器的其中一种创建方式与列表推导式很相似,这里先说一下列表推导式。
列表推导式
列表推导式又叫列表生成式,官方叫做 list comprehension。顾名思义,这个是用来生成列表的。
用法:
[x for x in iterable]
一般情况下,可以用list()函数将序列转换成列表,比如:
>>> list(range(1, 11))
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
上面的情况比较单一,如果复杂一点,比如要生成[1x1, 2x2, 3x3, ..., 10x10],这个时候就只能循环了,列表推导式就是用来简化这种情况的。
>>> [x * x for x in range(1, 11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
把要生成的元素x * x放在前面,后面跟for循环,就可以把列表创建出来。运用列表推导式,可以写出非常简洁的代码。
>>> L = ['Hello', 'World', 'IBM', 'Apple']
>>> [s.lower() for s in L]
['hello', 'world', 'ibm', 'apple']
生成器表达式
通过列表推导式,可以直接生成一个列表,但是内存是有限的,如果一个列表太大,或者只需要访问列表中的部分元素,那其余大部分元素占用的空间就浪费了,生成器就是用来解决这个问题的。
生成器在访问序列中的元素时,不是一下加载整个序列到内存,而是一边循环一边计算,也就是读取一个元素计算一次,这样如果序列很大就节省了大量空间。说白了,生成器就是一种特殊的迭代器。
生成器有两种创建方法,第一种与列表推导式类似,只需要把列表推导式中的方括号[]改成圆括号()即可创建一个生成器(generator)。
>>> L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x0000000001E74CA8>
>>> for i in g:
... print(i)
...
0
1
4
9
16
25
36
49
64
81
创建生成器的第二种方法,是通过生成器函数。所谓生成器函数,就是在一个函数中包含yield语句。
比如斐波那契函数:
>>> def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
return 'done'
... ... ... ... ... ... ...
带有 yield 的函数不再是一个普通函数,而是一个generator。
>>> fib(10)
<generator object fib at 0x0000000001DE6A40>
>>> list(fib(10))
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
需要注意的是,生成器函数和普通函数执行的流程是不一样的。普通函数是遇到 return 语句或者执行结束就返回。而生成器函数是遇到 yield 就返回一个迭代值,再次执行时从上次返回的 yield 语句处继续执行,看起来就像一个函数在正常执行的过程中被 yield 中断了数次,每次中断都会通过 yield 返回当前迭代值。
好像说的有点绕,简单来说,yield就是中断函数并返回迭代值,而且中断不会对函数变量造成影响即状态不变,返回迭代值之后继续执行函数。
再看看下面这个示例:
>>> def odd():
print('step 1')
yield 1
print('step 2')
yield(3)
print('step 3')
yield(5)
>>> odd()
<generator object odd at 0x0000000001DE6A98>
>>> for i in odd():
... print(i)
...
step 1
1
step 2
3
step 3
5
遇到yield就返回迭代值,这个返回类似return但不会退出函数(可以理解为挂起),然后继续执行函数,直到再次遇到yield。
另外,上面生成器函数fib()最后的retrun的值没有返回(在普通函数中是可以返回的)。因为,调用生成器函数并没有执行函数代码,而是返回了一个generator object,然后再从generator object中迭代取值的时候才会真正执行函数代码,所以调用生成器函数的时候并没有报异常并退出,return的值也没有返回。
在生成器中,无论迭代有没有完成,遇到return语句都会直接终止迭代并抛出StopIteration异常。。
这里顺便说一下迭代器,迭代器可以通过内置函数next()获取迭代器中的下一个元素,迭代完成时会报StopIteration异常。
>>> g = (x * x for x in range(5))
>>> next(g)
0
>>> next(g)
1
>>> next(g)
4
>>> next(g)
9
>>> next(g)
16
>>> next(g)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
在 for 循环里,无需处理 StopIteration 异常,循环会正常结束。但是在while循环中会抛出异常,这时,需要捕获异常才会继续执行return语句,return的返回值包含在StopIteration的value中。
>>> g=fib(6)
>>> while True:
x = next(g)
print('g:', x)
... ... ...
g: 1
g: 1
g: 2
g: 3
g: 5
g: 8
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
StopIteration: done
再来看上面的fib()函数的StopIteration异常捕获:
>>> g = fib(6)
>>> while True:
try:
x = next(g)
print('g:', x)
except StopIteration as e:
print('Generator return value:', e.value)
break
... ... ... ... ... ... ...
g: 1
g: 1
g: 2
g: 3
g: 5
g: 8
Generator return value: done
另一个示例,文件读取:
如果直接对文件对象调用 read() 方法,会导致不可预测的内存占用。好的方法是利用固定长度的缓冲区来不断读取文件内容。
如果读取的文件很大,yield会分批返回,有效地避免了内存占用问题,轻松实现文件读取。
>>> def read_file(fpath):
BLOCK_SIZE = 1024
with open(fpath, 'rb') as f:
while True:
block = f.read(BLOCK_SIZE)
if block:
yield block
else:
return
>>> g = read_file('users.txt')
>>> for i in g:
... print(i)
...
b'keith1:18:110\r\nkeith2:19:111\r\nkeith3:20:112\r\nkeith4:21:113'
参考:
https://docs.python.org/3/library/stdtypes.html#lists
https://docs.python.org/3/reference/simple_stmts.html#the-yield-statement
https://docs.python.org/3/reference/expressions.html#yieldexpr
生成器 yield的更多相关文章
- Python入门之迭代器/生成器/yield的表达方式/面向过程编程
本章内容 迭代器 面向过程编程 一.什么是迭代 二.什么是迭代器 三.迭代器演示和举例 四.生成器yield基础 五.生成器yield的表达式形式 六.面向过程编程 ================= ...
- PHP性能优化利器:生成器 yield理解
如果是做Python或者其他语言的小伙伴,对于生成器应该不陌生.但很多PHP开发者或许都不知道生成器这个功能,可能是因为生成器是PHP 5.5.0才引入的功能,也可以是生成器作用不是很明显.但是,生成 ...
- [PY3]——函数——生成器(yield关键字)
函数—生成器篇 1. 认识和区分可迭代or生成器 1.1 可迭代对象 当你建立了一个列表,你可以逐项地读取这个列表,这叫做一个可迭代对象 当你使用一个列表生成式来建立一个列表的时候,就建立了一个可迭代 ...
- 6 生成器 yield 协程
1.生成器 ----> 1 b = [x*2 for x in range(100000000000)] MemoryError: 想生成一个存放很多数据的列表,但是又不想内存占用太多 每次用一 ...
- day4 内置函数 迭代器&生成器 yield总结 三元运算 闭包
内置函数: 内置函数 # abs()返回一个数字的绝对值.如果给出复数,返回值就是该复数的模. b = -100 print(b) print(abs(b)) # all() 所有为真才为真,只要有一 ...
- PHP 生成器 yield理解
如果是做Python或者其他语言的小伙伴,对于生成器应该不陌生.但很多PHP开发者或许都不知道生成器这个功能,可能是因为生成器是PHP 5.5.0才引入的功能,也可以是生成器作用不是很明显.但是,生成 ...
- python3使用迭代生成器yield减少内存占用
技术背景 在python编码中for循环处理任务时,会将所有的待遍历参量加载到内存中.其实这本没有必要,因为这些参量很有可能是一次性使用的,甚至很多场景下这些参量是不需要同时存储在内存中的,这时候就会 ...
- Two---python循环语句/迭代器生成器/yield与return/自定义函数与匿名函数/参数传递
python基础02 条件控制 python条件语句是通过一条或多条语句的执行结果(Ture或者False)来执行的代码块 python中用elif代替了else if,所以if语句的关键字为:if- ...
- Python全栈之路8--迭代器(iter)和生成器(yield)
一.生成器( iter ) 从Python2.2起,生成器提供了一种简洁的方式帮助返回列表元素的函数来完成简单和有效的代码. 它基于yield指令,允许停止函数并立即返回结果.此函数保存其执行上下文, ...
- (转) Python Generators(生成器)——yield关键字
http://blog.csdn.net/scelong/article/details/6969276 生成器是这样一个函数,它记住上一次返回时在函数体中的位置.对生成器函数的第二次(或第 n 次) ...
随机推荐
- 2017-2018 Exp6 信息搜集与漏洞扫描 20155214
目录 Exp6 信息搜集与漏洞扫描 实验内容 信息收集 漏洞扫描 知识点 Exp6 信息搜集与漏洞扫描 收集渗透目标的情报是最重要的阶段.如果收集到有用的情报资料的话,可以大大提高对渗透测试的成功性. ...
- Selenium-Switch与SelectApi接口详解
Switch 我们在UI自动化测试时,总会出现新建一个tab页面.弹出一个浏览器级别的弹框或者是出现一个iframe标签,这时我们用WebDriver提供的Api接口就无法处理这些情况了.需要用到Se ...
- P4385 [COCI2009]Dvapravca
首先特判掉蓝点数量\(<2\)的情况.没有蓝点答案就是\(n\),有一个蓝点可以枚举一个红点,选择过这个蓝点和红点的一条线和在无穷远处的平行线(即这条线对应的两个半平面). 这里认为过一个点是与 ...
- post请求参数Json字符串包含数组的校验和处理
传入参数类型 {"aaa":"aaaa","bbb":"bbb","ccc":"ccc&q ...
- Java 多线程之 Thread 类 和 Runnable 接口初步使用
目录 Thread 类 Thread之定义线程类 Thread之开启线程 Runnable 接口 Runnable 之定义线程类 Runnable 之开启线程 @ Thread 类 Thread 类是 ...
- 有关ADO.NET基础中的基础的熟悉过程
现在对于ADO.NET基础的理解与记忆并不严谨和完善 所以,只写一点关于自己的理解,嗯,一种去转换思维理解的方法吧,算是吧 希望各位前辈或者同学,积极指出其中的错误和偏差 个人对于刚接触的ADO.NE ...
- C#集合与泛型集合
看到这个标题,大家应该就知道有泛型集合,就有非泛型集合 既然都是集合,咱们今儿就简单的来对比讲解下 需要记住的不算太多,理解记忆.理解记忆 2017-11-0411:39:09 C# 泛型集合之非泛型 ...
- POJ1094——拓扑排序和它的唯一性
比较模板的topological-sort题,关键在于每个元素都严格存在唯一的大小关系,而一般的拓扑排序只给出一个可能解,这就需要每趟排序的过程中监视它是不是总坚持一条唯一的路径. 算法导论里面的拓扑 ...
- TensorFlow训练MNIST数据集(1) —— softmax 单层神经网络
1.MNIST数据集简介 首先通过下面两行代码获取到TensorFlow内置的MNIST数据集: from tensorflow.examples.tutorials.mnist import inp ...
- Windows Defender还原误删文件
Win 10 新版本的Windows Defender隔离/删除的文件没有还原的选项,导致被误删的文件无法在威胁记录中恢复.经过尝试发现可以通过修改注册表添加 “还原” 选项 打开注册表,找到 HKE ...