python中的yield生成器详解
#原创,转载请先联系
在学习生成器之前,必须先了解一下迭代器。因为生成器就是一种特殊的迭代器,而且生成器用起来更加优雅。
迭代器的详解可以参考我的另一篇博文:https://www.cnblogs.com/chichung/p/9537969.html
先说一种比较简单的生成器,通过例子慢慢来体会什么是生成器。
# 列表生成式
L = [x for x in range(5)]
print(L) #简单的生成器
G = (x for x in range(5)) # G就是一个生成器,也是一个迭代器,迭代器也是可迭代对象,所以这个G也可以说是可迭代对象
print(next(G))
print(next(G))
print(next(G))
print(next(G))
print(next(G)) 输出:
[0, 1, 2, 3, 4]
0
1
2
3
4
把列表生成器的[]改为()就变成一个简单的生成器。由上面的例子,我们大概可以知道,生成器就是一个迭代器,把数据一个一个拿出来,可以减少内存的负担。
那么,yield又是一个什么东西呢?为什么说他优雅呢?
当我们写的代码输出的结果,想一个一个出来。有两种常用的方法:
方法1.我们可以创建一个迭代器类,然后把代码写进类里,用类来创建一个可迭代对象,然后用next()函数一个一个把结果迭代出来。
方法2.我们可以用代码函数的合适位置加上yield,这时候这个函数就变成一个生成器了,不需要再创建一个迭代器类,不需要再写__iter__,__next__方法了。这样一来不是很方便,很优雅吗?哈哈哈哈~
口说无凭,下面我们2个方法都做一下,让你们体会一下:
我们做一个斐波那契的数列生成器。斐波那契数列的第一个数是0,第二个数是1,第三个数是第一、二个数相加,第四个数是第二、三个数相加......
方法1:
class FeiboIterator():
def __init__(self):
self.a = 0
self.b = 1 def __iter__(self):
return self def __next__(self):
num = self.a
self.a,self.b = self.b,self.a+self.b
return num iterator = FeiboIterator()
print(next(iterator))
print(next(iterator))
print(next(iterator))
print(next(iterator))
print(next(iterator))
print(next(iterator))
print(next(iterator))
print(next(iterator)) 输出:
0
1
2
3
5
8
13
是不是很麻烦?又要初始化,又要写__iter__和__next__魔方方法。
方法2:
def feibo():
a = 0
b = 1
while True:
yield a # 假如yield后面紧接着一个数据,就会把数据返回,作为next()函数或者for ...in...迭代出的下一个值
a,b = b,a+b generator = feibo() print(next(generator))
print(next(generator))
print(next(generator))
print(next(generator))
print(next(generator))
print(next(generator))
print(next(generator))
print(next(generator)) 输出:
0
1
1
2
3
5
8
13
看!只有6行代码,是不是很elegant?关于这个程序是怎么运行的?yield是怎么运作的?我们等下就讲,现在需要注意几点:
1.上面代码的红色字那里!假如yield后面紧接着一个数据,就会把数据返回,作为next()函数或者for ...in...迭代出的下一个值。
2.假如函数中有yield,就不再是函数。而是一个能返回生成器的函数!注意!是返回,这个函数并不是一个生成器。(修正:这句话发现有错误,这个函数也是一个生成器)
3.拿到函数的生成器后,可以和迭代器一样,用next()函数获得下一个值。
好了,该来理解一下yield是怎么运作的了!
1.第一次唤醒生成器时,是从函数的起始位置开始,直到遇到yield,就会暂停函数,挂起函数。
2.第二次唤醒生成器时,是从yield断点处开始,直到又遇到yield。
3.当生成器已经没有yield,再使用next,则抛StopIteration异常。
然后,我们来理一下上面用yield写的代码。
第一次用next()唤醒生成器时,从函数的开头开始运行,遇到yield a,返回a,然后暂停函数,并记住函数是运行到这个位置的。
第二次唤醒生成器,从yield a断点处开始,然后a,b开始赋值,while True循环又遇见yield a,返回a,然后暂停函数,并记住函数是运行到这个位置的。
下面唤醒多少次都是这个道理,但是由于这个函数是死循环,所以不会没有yield,也就不会抛出StopIteration异常。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
其实yield还能接受值,用send方法进行传入。代码体会一下:
def gg():
i = 1
while True:
recv = yield i
print("接收到一个值:",recv)
i += 1 generator = gg() print(next(generator))
print(generator.send(""))
print(generator.send("")) 输出:
1
接收到一个值: 456
2
接收到一个值: 789
3
实现过程和上面的例子一样。
要懂得的是,yield = a,会返回a。
b = yield,会把yield接收的值赋值给b。
python中的yield生成器详解的更多相关文章
- Python中的高级数据结构详解
这篇文章主要介绍了Python中的高级数据结构详解,本文讲解了Collection.Array.Heapq.Bisect.Weakref.Copy以及Pprint这些数据结构的用法,需要的朋友可以参考 ...
- Python中格式化format()方法详解
Python中格式化format()方法详解 Python中格式化输出字符串使用format()函数, 字符串即类, 可以使用方法; Python是完全面向对象的语言, 任何东西都是对象; 字符串的参 ...
- python中的tcp示例详解
python中的tcp示例详解 目录 TCP简介 TCP介绍 TCP特点 TCP与UDP的不同点 udp通信模型 tcp客户端 tcp服务器 tcp注意点 TCP简介 TCP介绍 TCP协议 ...
- Python中的yield生成器的简单介绍
Python yield 使用浅析(整理自:廖 雪峰, 软件工程师, HP 2012 年 11 月 22 日 ) 初学 Python 的开发者经常会发现很多 Python 函数中用到了 yield 关 ...
- python中的 zip函数详解
python中zip()函数用法举例 定义:zip([iterable, ...]) zip()是Python的一个内建函数,它接受一系列可迭代的对象作为参数,将对象中对应的元素打包成一个个tuple ...
- python中的buildin函数详解(第一篇)
这会是很长的一个帖子,因为我打算从python最基础的东西开始,尝试去完全的掌握它,buildin中有一些常用的函数比如 abs, open, setattr, getattr, 大家都很了解他们的用 ...
- python中的builtin函数详解-第二篇
classmethod(function) 这里不过多说明这个builtin方法的具体用法,python的文档和help函数已经给了这个方法充足的使用说明,所以我这里要说的时关于 classmetho ...
- python中的Queue(队列)详解
一.Queue简介 python中的队列分类可分为两种: 1.线程Queue,也就是普通的Queue 2.进程Queue,在多线程与多进程会介绍. Queue的种类: FIFO: Queue.Que ...
- Python中标准模块importlib详解
1 模块简介 Python提供了importlib包作为标准库的一部分.目的就是提供Python中import语句的实现(以及__import__函数).另外,importlib允许程序员创建他们自定 ...
随机推荐
- mysql数据备份和还原
MySQL是一个永久存储数据的数据库服务器.如果使用MySQLServer,那么需要创建数据库备份以便从崩溃中恢复.mysql提供了一个用于备份的实用程序mysqldump. 1.普通.sql文件中的 ...
- NO12——快速幂取模
long long quickmod(long long a,long long b,long long m) { ; while(b)//用一个循环从右到左便利b的所有二进制位 { )//判断此时b ...
- Spring MVC温故而知新 – 参数绑定、转发与重定向、异常处理、拦截器
请求参数绑定 当用户发送请求时,根据Spring MVC的请求处理流程,前端控制器会请求处理器映射器返回一个处理器,然后请求处理器适配器之心相应的处理器,此时处理器映射器会调用Spring Mvc 提 ...
- PHP整数取余返回负数解决办法
<?php $num1 = 1494313163777; $num2 = 9999; //直接计算取余会出错,出现负数 -8779 //echo $num1 % $num2;exit; //算上 ...
- 《SQL入门经典》总结
<SQL入门经典>这本书从考试前就开了个头,一直到前两天才看完,拉的战线也够长的.放假来了,基本上什么内容都不记得了.好不容易看完了,就赶紧总结一下吧! 该书分为两大部分,第一部分是第1~ ...
- python 的sets list dictionary
http://blog.csdn.net/joseph_happy/article/details/6717412 http://blog.csdn.net/joseph_happy/article/ ...
- HTML5<canvas>标签:使用canvas元素在网页上绘制四分之一圆(3)
前几天自己做了个四分之一的圆,放到手机里面测试.效果不是很好.于是今天通过查资料,找到了canvas.自己研究了一天,发现可以使用canvas画圆.代码如下: <!doctype html> ...
- 【转】Word单引号‘’替换为正确的单引号(plsql参数的单引号)
转自 http://jingyan.baidu.com/article/39810a23db44b5b636fda6f2.html 问题描述: 单引号明显不一样,替换不了 解决方案,如下图
- [IOI2007 D1T1]Miners 矿工配餐
题目大意:有$2$个煤矿,$n$天.每天给一个煤矿送餐(共有有$3$种餐),价值为它与前面两次送餐(如果有的话)不同的种类数.最大化价值. 题解:看到只有三种餐,考虑状压$DP$.$f_{i,j,k, ...
- wmic的用法
原始文章链接:http://blog.sina.com.cn/s/blog_5fb265c70100w4d0.html 一.wmic的基本命令格式简析 经常看网上的相关资料的话,读者可能会对wmic有 ...