生成器
通过列表生成式,可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。如果要创建一个包含100万个元素的列表,不仅占用很大的存储空间,或者仅仅需要访问前面几个元素,加载入内存的其他元素就充分浪费内存空间.
所以,如果列表元素可以按照某种算法推算出来,那是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的内存空间。在Python中,这种一边循环一边计算的机制(通俗说就是需要一个值取一个值,而且只会占用一个元素的内存空间),称为生成器(generator)

1. 列表生成式****
描述:生成一个列表的表达式,一般列表[1,2,3],如下是把for x in range(10)内容作遍历放到前面的x
注意:第一个元素和for后的元素要保持一致,如前面是x后面也要是x

In [1]: [x for x in range(10)]
Out[1]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [3]: [x*2 for x in range(10)]             ##可以对列表做操作,生成新的列表
Out[3]: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

生成式中存放函数

先定义一个函数
In [5]: def f(n):...:     return n**3for循环调用
In [6]: [f(x) for x in range(10)]
Out[6]: [0, 1, 8, 27, 64, 125, 216, 343, 512, 729]
In [7]: a=[f(x) for x in range(10)]
In [8]: type(a)
Out[8]: list

两个元素赋值(注:赋值的元素数量要两边相等)

In [9]: t=('393',8)
In [10]: a,b=t
In [11]: a
Out[11]: '393'
In [12]: b
Out[12]: 8

  

2. 生成器****
描述:通过如下方式只能取得一个对象,如果是列表表达式,有10个值,相当于是10盘已经作好的菜,什么时候要吃就吃,列表也是可以这样操作,但是存在一个问题它占用内存空间,生成器就相当于它是一个厨师,什么时候要吃一道菜时,可以让它做出来,它只需要调用一个方法,不吃就不会占用空间,所以当列表数量特别大时,列表相当占用内存空间
生成器的两种创建方式
创建方式a. s=(x for x in range(10))

In [13]: s=(f(x) for x in range(10))            #修改封闭方式,把中括号修改成小括号
In [14]: print(s)
<generator object <genexpr> at 0x7f7ddef4b0a0>  ##生成器对象In [15]: [f(x) for x in range(100000000000000000000)]
Killed

使用生成器的next方法来调用值(next方法只能按顺序来取值)

In [3]: s=(x for x in range(10))
In [4]: s.__next__()        ##在python2上调用没有下划线,但是在python3是内部特殊方法的调用,不建议这样使用
Out[4]: 0
In [5]: s.__next__()
Out[5]: 1
In [6]: next(s)            ##python3上建议使用的内置方法,超出range(10)的范围会报错,因为迭代结束
Out[6]: 2
In [7]: next(s)
Out[7]: 3

生成器本向是一个可迭代对象,所以可以使用for循环
描述:a.s是一个数,遍历时会把第一个数取出,实际是for对s在内部进行一个next的调用来取值,第一次把next的值赋值给i,就可以打印出来了0,再循环再回来取得1,然后之前的0就会作为垃圾被回收,即使打印100万个数也只是占用一个数的内存空间,因为没有被引用的会被python的解释器所回收
b.for反复的调用next,但是按照常理,到最后一个数时代表迭代结束,应该会报错误StopIteration,这时for循环通过异常检测出来,也就是通过except的关键字来捕错误,一旦发生错误except就可以取得,来判断是否迭代结束,然后就直接返回不再做任何的处理

In [8]: for i in s:...:     print(i)...:
4
5
6
7
8
9

  

b. yield创建方式
一般函数

In [4]: def f():...:     return 1...: f()...:
Out[4]: 1

yield:(主要用于协程)
执行顺序

In [12]: def f():...:     print('ok')...:     yield 1          ##类型于return的功能,把1返回,如果下面再有代码不会执行,除非再加yield...:     print('ok')...:     yield 2...:                     ##在yield 2后面有一个默认的return none,代表函数结束
In [13]: a=f()               ##f()是一个生成器对象,赋值给a,这个结束后不会执行f,不会执行fIn [14]: print(a)
<generator object f at 0x7f013e847a40>  ##是一个生成器对象,只要有yield就是生成器对象In [15]: next(a)
ok
Out[15]: 1  #return 1In [16]: next(a)
ok
Out[16]: 2  #return 2

  

for循环调用原理
描述:调用f()生成器对象,调用next,第一次调用next时,print('ok'),然后返回1,再把1赋值给i,再next,从yield1开始走,print('ok'),返回2,再赋值给i,print(2),第三次再进去函数发现没有yield在会
发生迭代错误,for捕捉异常,迭代结束
注:for i in 后面加的是可迭代对象,for i in后面可以加一个列表[1,2,3],但是列表不是迭代器,因为假设a=[1,2,3],a.时就没有next方法,可迭代对象是内部有__iter__()方法的才是,列表、元组、字典
都有inter方法

In [17]: for i in f():...:     print(i)...:
ok
1
ok
2
#for内部实际运行过程
In [18]: for i in f():...:     while True:...:         i=next(f())

  

c.生成器的第二个方法send
描述:send与next功能相似,而且还可以向函数传入值,也就是可以给yield前面的变量传入值

In [48]: def boo():...:     print('ok1')...:     yield 1...:     print('ok2')...:     yield 2
In [49]: b=boo()
In [50]: next(b)
ok1
Out[50]: 1
In [51]: b.send('bbb')   ##没报错
ok2
Out[51]: 2

第一次send时只能使用none,因为它不知道赋值给那个变量,如果第一次send前有next,即使不知道传入给那个变量也不会报错
流程:b.send(None)与next(b)一样,进入函数体,打印ok1,到count=yield1,这里yield 1是直接返回1,第2次b.send('bbb'),这里传入bbb值会赋值给count,再执行打印count,yield 2直接返回2
作用:有时需要与程序交互,需要在调用它时给它一些参数,再用send传入给它一个指导作用

In [52]: def boo():...:     print('ok1')...:     count=yield 1...:     print(count)...:     yield 2
In [53]: b=boo()
In [54]: b.send(None)     ##相当于next(b)
ok1
Out[54]: 1                ##已经返回1
In [55]: b.send('bbb')
bbb
Out[55]: 2

  

3.通过生成器yield实现伪并发
描述:很久前CPU只有颗,在同一时刻,CPU只能执行一个任务,但是却做到"伪并"发的效果,如在电脑上既看电影,同时又在QQ聊天,实际是在两个程序之间不段的切换来执行,只是在切换过程中速度快到人所无法感知,如下不太贴切吃苹果就是模拟这种伪并发,一个产苹果,A,B同时吃的简单例子

In [5]: import timeIn [6]: def consumer(name):                       ##吃苹果的人...:     print("%s Prepare apple!" %name)      ##传入参数A是人名,准备苹果,接着是B...:     while True:...:         apple = yield                     ##yield状态停住,下次有参数传入,apple可以接收...:         print("apple[%s]is coming,[%s]eat!"%(apple,name))...:         In [7]: def producer(name):                       ##生产苹果的人,一产一吃达到这种并发的效果...:     c = consumer('A')             ##创建两个变量,执行consumer函数分别传入参数A,B...:     c2 = consumer('B')            ##这两行生成一个生成器对象...:     c.__next__()                  ##通过next执行,返回,A准备吃苹果...:     c2.__next__()                 ##通过next执行,返回,B准备吃苹果...:     print("I am ready to eat!")...:     for i in range(2):...:         time.sleep(1)...:         print("prepare two apples!")  ##就可以准备,模拟停止了1秒钟,准备两个苹果...:         c.send(i)  ##发送i给c生成器对象,c带i进入到consumer函数apple=yield中,i就给apple这个变量,for i in range(2),从0开始,apple=0,就打印apple[0]is coming,[A]eat!,然后while循环继续又回到yield,c.send(i)就执行完成,再到c2.send(i)执行...:         c2.send(i)In [8]: producer("reid")
A Prepare apple!
B Prepare apple!
I am ready to eat!
prepare two apples!
apple[0]is coming,[A]eat!
apple[0]is coming,[B]eat!
prepare two apples!
apple[1]is coming,[A]eat!
apple[1]is coming,[B]eat!

  

4.斐波那契数列

# 0 1 1 2 3 5 8 13 21
In [18]: def fibo(max):...:     n,before,after=0,0,1  ##n是第几位,before前一位数,after是后一位数...:     while n < max:        ...:         print(after)      ##从1开始打印...:         before,after=after,before+after
#第2位1的值已经打印出来,要做相应的计算,一开始before是0,after是1,移位后before是1,after是before+after=0+1...:         n = n + 1         ##让n+1进行下一次打印,第二次打印after,从1还是变成1
In [32]: fibo(6)
1
1
2
3
5
8In [33]: def fibo(max):...:     n, before, after=0, 0, 1...:     while n < max:...:         print(before)...:         before,after=after,before+after...:         n = n + 1...:         In [34]: fibo(6)   ##打印before从0开始
0
1
1
2
3
5

补充:before,after=after,before+after运行原理

before=1
after=2
before,after=after,before+after
描述:先从右边开始运行before,after=(after=2),(before+after=1+2=3),再给左边赋值
使用yield来返回,使用next来调用斐波那契数列
In [35]: def fibo(max):...:     n,before,after=0,1,1...:     while n<max:...:         yield before  #yield有断层,第一次执行完后,把这个状态保存了,下次再从这里开始...:         before,after=after,before+after...:
In [37]: fibo(6)
Out[37]: <generator object fibo at 0x7f013d4a7990>   #生成器对象,传入的6并不在内存地址,在调用时才会取,而且有限制
In [38]: a=fibo(5)
In [39]: next(a)
Out[39]: 1
In [40]: next(a)
Out[40]: 1
In [41]: next(a)
Out[41]: 2

  

转载于:https://www.cnblogs.com/reid21/articles/8645697.html

Python攻克之路-生成器相关推荐

  1. Python攻克之路-xml模块

    xml模块 描述:xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但是Json使用起来更简单,json还没有诞生时,xml已经开始使用很久,至今很多传统公司如金融行业很多系统的接口 ...

  2. Python攻克之路-random模块

    random模块 描述:生成随机数 random常用方法 random In [2]: random.random() #0-1之间 Out[2]: 0.2295625620781645 randin ...

  3. Python攻克之路-网络编程(文件上传实现思路)

    需求:一个server,一个client,实现client把某个文件传到server中某个目录中 分析:实际是实现数据传输,设定一个命令和一个参数(上传的内容),连接后,让用户输入命令和要传送的内容, ...

  4. Python攻克之路-高阶函数

    高阶函数 在数学和计算机科学中,高阶函数是至少满足下列一个条件的函数: 接受一个或多个函数作为输入 输出一个函数 在数学中它们也叫做算子(运算符)或泛函.微积分中的导数就是常见的例子,因为它映射一个函 ...

  5. Python攻克之路-hashlib模块

    hashlib模块 描述:加密模块,从明文加密成密文,主要是md5和sha md5 In [13]: import hashlib In [14]: m=hashlib.md5() In [15]: ...

  6. Python 进阶之路 (九) 再立Flag, 社区最全的itertools深度解析(上)

    前言 大家好,今天想和大家分享一下我的itertools学习体验及心得,itertools是一个Python的自带库,内含多种非常实用的方法,我简单学习了一下,发现可以大大提升工作效率,在sf社区内没 ...

  7. Python文档字符串生成器:基于CodeBERT,支持Google、Numpy等多种输出格式

    木易 发自 凹非寺  量子位 报道 | 公众号 QbitAI 又一款懒人神器问世了: Visual Studio Code的扩展,基于CodeBERT的Python文档字符串生成器. 看来现在,这群偷 ...

  8. Python之迭代器和生成器(Day17)

    一.可迭代对象(iterable) 刚才说过,很多容器都是可迭代对象,此外还有更多的对象同样也是可迭代对象,比如处于打开状态的files,sockets等等.但凡是可以返回一个迭代器的对象都可称之为可 ...

  9. python之路 mysql 博客园_教为学:Python学习之路(二):MySQLdb的几种安装方式,以及用Python测试连接MySql...

    教为学:Python学习之路(二):MySQLdb的几种安装方式,以及用Python测试连接MySql Easy_install安装MySQLdb 很简单,以至于我不晓得该怎么说.一句话. sodu ...

  10. python有关迭代器和生成器的面试题_【面试题 | Python中迭代器和生成器的区别?】- 环球网校...

    [摘要]今天给大家解答一道Python常见的面试题,希望这个面试栏目,给那些准备面试的同学,提供一点点帮助!小编会从最基础的面试题开始,每天一题.如果参考答案不够好,或者有错误的话,麻烦大家可以在留言 ...

最新文章

  1. 人工智能改变未来教育的5大方式
  2. js脚本 处理js注入
  3. 西南交大计算机专硕就业怎么样,国内四所交通大学,有985也有211,就业、深造容易,值得报考...
  4. JSP,JSF和EL简介
  5. hwclock: Open of /dev/rtc failed, errno=19: No such device.
  6. torch.nn.parameter.Parameter分析
  7. windows下php命令行模式错误信息
  8. java切割文件出现1k_java实现把一个大文件切割成N个固定大小的文件
  9. php 保存json格式数组 json_encode /u 不转义
  10. 小程序学习笔记(4)-猫眼电影案例
  11. Office Tool Plus v8.2.4.0 安装Office组件小工具
  12. html修改鼠标手势,css要怎么设置鼠标手势?
  13. 无线系列-WiFi信号波形产生器
  14. php长微博,用Word一键发布长微博
  15. 公司新加了一台友宝自动售货机引发的思考-适配器模式
  16. LeetCode笔记05:最长公共前缀
  17. MSP430F5529LP(一)IIC与OLED的HELLOWRLD
  18. Python数据结构11:树的实现,树的应用,前中后序遍历,二叉查找树BST,平衡二叉树AVL树,哈夫曼树和哈夫曼编码
  19. ​PDF虚拟打印机(pdfFactory) v5.12 官方版
  20. 刘大拿python_零基础Python知识点回顾(一)

热门文章

  1. 注意sizeof()返回的数无符号数,有符号数遇到无符号数时变成无符号数
  2. 如何在 Mac 上使用“接力”回到上次离开的地方?
  3. MAMP Pro for Mac(PHP/MySQL开发环境)
  4. 18 Strings for Mac(Xcode文件翻译工具)
  5. SmartSVN 14 for Mac(多平台SVN客户端)
  6. DVD-Cloner 2021 for mac(DVD光盘刻录工具)
  7. 如何在Mac上将您的Apple ID更改为其他电子邮件地址?
  8. 通信原理实践(五)——2PSK 与2DPSK 通信系统
  9. win7下声音图标消失的解决办法
  10. windows 下 MyEclipse 运行hadoop 出错