大聊PYthon----生成器
再说迭代器与生成器之前,先说一说列表生成式
列表生成式
什么是列表生成式呢?
这个非常简单!
先看看普通青年版的!
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> b = []
>>> for i in a:b.append(i+1)
...
>>> b
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> a = b
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
再看看原值修改版的!
a = [1,3,4,6,7,7,8,9,11] for index,i in enumerate(a):
a[index] +=1
print(a)
再看看文艺青年版的!
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> a = map(lambda x:x+1, a)
>>> a
<map object at 0x101d2c630>
>>> for i in a:print(i)
...
2
3
4
5
6
7
8
9
10
11
再看看装逼青年版
>>> a = [i+1 for i in range(10)]
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
这就叫做列表生成!
列表生成的主要作用是使代码更简洁
说完了列表生成式,那现在就开始说说生成器
生成器
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。(说白了就是浪费内存)
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
生成器的机制:
a、生成器只有在调用的时候才会生成相应的数据.
先看一段代码:
>>> Good_man = [i*2 for i in range(100)]
>>> Good_man
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72
, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134
, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190,
192, 194, 196, 198]
在路上你遇到了一个好人,他说:我能把你手里的100块钱变成200块,只要你给我,我就给你变!于是你就给他100块,很快的时间,他就把变的200块钱给你了,也没有贪图你一分钱!
再看一段代码:
>>> Bad_man = (i*2 for i in range(100))
>>> Bad_man
<generator object <genexpr> at 0x000000000066BE08> # 生成器
>>>
遇到好人之后,他将100块变成了200块,于是你的心理美滋滋,想着如果再能碰到这样的人就好,当你走着走着,突然看到一个很道貌盎然的男人,这个男人在路边看到了一个好人给他变钱,于是这个男人想把你的钱骗走,于是他就跟你说,他也能把100变为200,于是你就把钱给他了,但是他没有变出来,不是他不会变,而是他不想变,你看到他没给你钱于是你想朝他要 ,你先朝他要2块钱,他也就只给你两块钱,你想要10块,他只给你10块,多一分钱都不会给你,他就是这么吝啬!他不会一起把钱全部给你,只会两块两块的给你,直到把200块钱都给你,看下面代码!
>>> Bad_man = (i*2 for i in range(100))
>>> for i in Bad_man:
... print(i)
...
0
2
4
·
·
·
·
·
194
196
198
b、只记录当前位置,只有一个__next__()方法.(在python2.7中是next( ))
Bad_man = (I*2 for i in range(1000000)
for i in Bad_man:
print(i) #输出
0
2
4
6
8
·
·
·
·
147946 # 突然在这里发生了错误 Traceback (most recent call last):
File "<stdin>", line 2, in <module>
KeyboardInterrupt
>>> ^X
File "<stdin>", line 1 ^
SyntaxError: invalid syntax
于是你想查找出现错误后的下一个数,通过
>>> Bad_man.__next__()
147948
找到了错误的一下个数,但是你想能不能找到出现错误的数的前几个代码呢?于是你就查找各种资料,结果发现不能,于是经过查找,发现,只能一个个的查找后面的数值,而且只能用一种__next__()方法,想查找前面的数值是不可能的了!
用函数来实现生成器
generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。
比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:
1, 1, 2, 3, 5, 8, 13, 21, 34, ...
斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:
def fib(max):
n, a, b = 0, 0, 1
while n < max:
print(b)
a, b = b, a + b
n = n + 1
return 'done'
fib(10)
输出结果:
1
1
2
3
5
8
13
21
34
55
仔细观察,可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。
也就是说,上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print(b)改为yield b就可以了:
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
return 'done' # return的作用是 程序异常时打印出消息
print(fib(10))
这就是定义generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator:
输出结果:
<generator object fib at 0x00000000006DBD00>
怎么样?很眼熟吧!
这里,最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
f = fib(10)
print(f)
print(f.__next__())
print(f.__next__())
print(f.__next__())
print(f.__next__())
print("下次玩的舒服点哦!")
print(f.__next__())
print(f.__next__()) # 输出
<generator object fib at 0x0000000000AD5D00>
1
1
2
3
下次玩的舒服点哦!
5
8
13
在上面fib的例子,我们在循环过程中不断调用yield,就会不断中断。当然要给循环设置一个条件来退出循环,不然就会产生一个无限数列出来。
同样的,把函数改成generator后,我们基本上从来不会用next()来获取下一个返回值,而是直接使用for循环来迭代:
f = fib(10)
print(f)
for n in f:
print(n)
# 打印
<generator object fib at 0x0000000000665D00>
1
1
2
3
5
8
13
21
34
55
但是用for循环调用generator时,发现拿不到generator的return语句的返回值。如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中:
g = fib(10)
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
g: 13
g: 21
g: 34
g: 55
Generator return value: done
大聊PYthon----生成器的更多相关文章
- python——生成器
python——生成器 通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个 ...
- 大聊Python----协程
协程 协程,又称微线程,纤程.英文名Coroutine.一句话说明什么是线程:协程是一种用户态的轻量级线程. 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来 ...
- 小学生都能学会的python(生成器)
小学生都能学会的python(生成器) 1. 生成器 生成器的本质就是迭代器. 生成器由生成器函数来创建或者通过生成器表达式来创建 # def func(): # lst = [] # for i i ...
- 【python之路29】python生成器generator与迭代器
一.python生成器 python生成器原理: 只要函数中存在yield,则函数就变为生成器函数 #!usr/bin/env python # -*- coding:utf-8 -*- def xr ...
- Python - 和我聊Python节目最新一期介绍 - 257期:使用超级电脑,Python,射电天文学知识来探索银河系
今天,给大家简单介绍和我聊Python的最新一期节目,第257期:使用超级电脑,Python,射电天文学知识来探索银河系. 听着标题就觉得高大上,是的,我也是这么认为的.这次请的嘉宾来头很大,来自国际 ...
- Python - 翻译Talk Python To Me (和我聊Python) 播客
“和我聊Python”是一个美国的聊天播客,英文名Talk Python To Me,类似于喜马拉雅的音频课程节目,只不过这个主题是编程语言Python.该节目从2015年的节目到现在,已经超过256 ...
- 让大蛇(Python)帮你找工作
前段时间用Python实现了一个网络爬虫(让大蛇(Python)帮你找工作),效率总体还可以,但是缺点就是每次都需要手动的去触发,于是打算对该爬虫加上Timer,经过网上一番搜索以及API的查询,发现 ...
- Python生成器-博文读后感
Windows 10家庭中文版,Python 3.6.4, 上午看过了一篇讲Python生成器的博文: 提高你的Python: 解释‘yield’和‘Generators(生成器)’(英文原文) 这篇 ...
- Python 生成器 (generator) & 迭代器 (iterator)
python 生成器 & 迭代器 生成器 (generator) 列表生成式 列表生成式用来生成一个列表,虽然写的是表达式,但是储存的是计算出来的结果,因此生成的列表受到内存大小的限制 示例: ...
- python生成器学习
python生成器学习: 案例分析一: def demo(): for i in range(4): yield i g=demo() g1=(i for i in g) #(i for i in d ...
随机推荐
- 小程序解密 encryptedData 获取 unionID 等信息
index.php <?php include_once "wxBizDataCrypt.php"; // $appid 由小程序微信官方后台获取 $appid = 'wx4 ...
- linux的一些机制Signal, Fork,
signal(SIGCHLD, SignalHandler); 注册软中断,对应的api close(socket); ret=fork(): 父进程,返回子进程的pid. 子进程返回0, 出错返回& ...
- websocket服务器+客户端
<?php $demo = new ws('192.168.90.47',12345); $demo->run(); class ws { //当前服务端主连接 private $curr ...
- MySQL专题3 SQL 优化
这两天去京东面试,面试官问了我一个问题,如何优化SQL 我上网查了一下资料,找到了不少方法,做一下记录 (一). 首先使用慢查询分析 通过Mysql 的Slow Query log 可以找到哪些SQ ...
- 两个float 怎么比较大小
转自:http://blog.csdn.net/mydriverc2/article/details/49888947 float 类型不能比较相等或不等,但可以比较>,<,>=,& ...
- sql语句左链接left join--3张表关联
表A---------------------------------关联第一张表B-----------------------关联第二张表c select * fomr 表名A left join ...
- openstack的网络配置
首先在浏览器输入咱们的控制节点的ip地址登陆horizon,也就是dashboard控制页面 输入好用户名与密码,这时输入的用户名与密码会与我们的老大哥keystone进行认证.确认你输入的这个用户有 ...
- Shell脚本修改Nginx upstream配置文件
#!/bin/bash ##################################################### # Name: change_nginx_upstream_conf ...
- 「美团 CodeM 资格赛」跳格子
题目描述 nnn 个格子排成一列,一开始,你在第一个格子,目标为跳到第 n 个格子.在每个格子 i 里面你可以做出两个选择: 选择「a」:向前跳 ai 步. 选择「b」:向前跳 bi 步. 把每步 ...
- 洛谷 P3924 康娜的线段树 解题报告
P3924 康娜的线段树 题目描述 小林是个程序媛,不可避免地康娜对这种人类的"魔法"产生了浓厚的兴趣,于是小林开始教她\(OI\). 今天康娜学习了一种叫做线段树的神奇魔法,这种 ...