python_10 迭代器和生成器
迭代器协议:
1.迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个Stopiteration异常,以终止迭代(只能往后走不能往前退)
2.可迭代对象:实现了迭代器协议的对象(如何实现:对象内部定义_iter_方法)
3.协议是一种约定,可迭代对象实现了迭代器协议,python的内部工具(如for循环,sum,min,max函数等)使用迭代器协议访问对象
for循环机制:
for循环的本质:循环所有对象,全都是使用迭代器协议。
(字符串,列表,元组,字典,集合,文件对象)这些都不是可迭代对象,只不过在for循环时,调用了他们内部的_iter_方法,把他们变成了可迭代对象
然后for循环调用可迭代对象的_next_方法去取值,而且for循环会捕捉Stopiteration异常,以终止迭代。
- s='abc'
- s_i=s.__iter__()
- print(s_i.__next__())
- print(s_i.__next__())
- print(s_i.__next__())
- print(s_i.__next__())#抛StopIteration异常
- >>>a
- >>>b
- >>>c
- >>>a
- Traceback (most recent call last):
- b
- File "E:/ch/Pylearning/Learning_09.py", line 115, in <module>
- c
- print(s_i.__next__())
- StopIteration
for循环的本质:
- l=[1,2,3]
- for i in l:#i_l=l.__iter__() i_l.__next__()
- print(i)
- #while循环完成for循环工作
- s='qwer'
- i=0
- while i<len(s):
- print(s[i])
- i+=1
但while循环不能遍历字典、集合、文件。
能被for循环遍历的对象都有__iter__()方法。
- f=open('a.txt','r+',encoding='utf-8')
- iter_f=f.__iter__()
- print(iter_f.__next__(),end='')
- print(iter_f.__next__(),end='')
- print(iter_f.__next__(),end='')
- print(iter_f.__next__(),end='')
for循环就是基于迭代器协议提供了一个统一的可以遍历所有对象的方法,在遍历之前,先调用对象的__iter__方法将起转换成一个迭代器,然后使用迭代器协议去实现循环访问,这样所有的对象就都可以通过for循环来遍历了。
用while循环模拟for循环机制:
- dic={'a':1,'b':2,'c':3}
- iter_d=dic.__iter__()
- while True:
- try:
- print(iter_d.__next__())
- except StopIteration:
- print('迭代完成')
- break
- >>>a
- b
- c
- 迭代完成
next()方法是系统自带方法,本质上也是调用__next__()方法
- l=[1,2,3]
- a=l.__iter__()
- print(next(a))#next()————》调用a.__next__()方法
只要遵循迭代器协议,那么该对象就是可迭代对象
生成器:
生成器:可以理解为一种数据类型,这种数据类型自动实现了迭代器协议(其他的数据类型需要调用自己内置的__iter__()方法),所以生成器就是可迭代对象
生成器分类及在python中的表现形式:
1.生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结构。yield语句一次返回一个结果,每个结果中间,挂起函数的状态,以便下次从它离开的地方继续执行.yield相当于return,但是可以在一个函数中使用多次。yield相当于封装了__iter__()方法,直接得到生成器对象。
- def test():
- yield 1
- yield 2
- yield 3
- yield 4
- g=test()
- print(g.__next__())
- print(g.__next__())
- print(g.__next__())
- print(g.__next__())
- >>>1
- 2
- 3
- 4
2.生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表
三元表达式
- #三元表达式
- name='ss'
- #如果name='alex'返回'sb'否则返回'hand'
- r='sb' if name=='alex' else 'hand'
- print(r)
列表解析:
- #将列表中放入10个鸡蛋
- l1=[]
- for i in range(1,11):
- l1.append('鸡蛋%s'%i)
- print(l1)
- >>>['鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4', '鸡蛋5', '鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9', '鸡蛋10']
- #列表解析的方式
- l2=['鸡蛋%s'%i for i in range(1,11)]
- print(l2)
- >>>['鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4', '鸡蛋5', '鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9', '鸡蛋10']
- l3=['鸡蛋%s'%i for i in range(1,11) if i<5]#没有四元表达式
- print(l3)
- >>>['鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4']
生成器表达式:
1.把列表解析的[]换成()得到的就是生成器表达式
2.列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存
- l2=['鸡蛋%s'%i for i in range(1,11)]
- #生成器:
- l4=('鸡蛋%s'%i for i in range(1,11))
- print(l4)
- print(l4.__next__())
- print(l4.__next__())
- print(next(l4))
- print(next(l4))
- >>><generator object <genexpr> at 0x000001FFD4A3C1A8>
- 鸡蛋1
- 鸡蛋2
- 鸡蛋3
- 鸡蛋4
3.pyhton不但使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。例如:sum函数是python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以,我们可以直接这样计算一系列值的和:
- l=[1,2,3,4,5,6,7,8,9,7,4,6,4,1]
- print(sum([1,2,3,4,5,6]))
- print(sum(i for i in range(0,1000000)))#生成器表达式方式
yield:
使用第一次__next__()则表示函数运行到第一个yield,使用第二次__next__()则表示函数从第一个yield运行到第二个yield,以此类推。。。
- import time
- def test():
- print('开始生孩子了')
- yield '我'
- time.sleep(3)
- print('又开始生孩子了')
- yield '我的孩子'
- time.sleep(3)
- print('又又开始生孩子了')
- yield '我的孩子的孩子'
- res=test()
- print(res.__next__())
- print(res.__next__())
- print(res.__next__())
- >>>开始生孩子了
- 我
- >>>又开始生孩子了
- 我的孩子
- >>>又又开始生孩子了
- 我的孩子的孩子
生成器函数:
例1:
- def product_baozi():
- for i in range(1,100):
- print('生产包子中')
- yield '包子%s'%i
- print('卖包子')
- p=product_baozi()
- baozi1=p.__next__()
- print(baozi1)
- baozi2=p.__next__()
- print(baozi2)
- >>>生产包子中
- 包子1
- 卖包子
例2:
- def product_egg():
- for i in range(1,1000):
- yield '第%s个鸡蛋'%i
- p=product_egg()
- print(p.__next__())
- print(p.__next__())
- print(p.__next__())
- print(p.__next__())
- print(p.__next__())
- print(p.__next__())
- print(p.__next__())
- print(p.__next__())
- >>>第1个鸡蛋
- 第2个鸡蛋
- 第3个鸡蛋
- 第4个鸡蛋
- 第5个鸡蛋
- 第6个鸡蛋
- 第7个鸡蛋
- 第8个鸡蛋
for循环遍历生成器:
- def product_egg():
- for i in range(1,1000):
- yield '第%s个鸡蛋'%i
- p=product_egg()
- for i in product_egg():
- print(i)
生成器总结:
- def get_populartion():
- with open('xxx','r',encoding='utf-8') as f:
- for i in f :
- yield i
- p=get_populartion()
- print('全国总人口约为%d'%sum(eval(i)['人口'] for i in p ))
- def test():
- for i in range(0,4):
- yield i
- t=test()
- # for i in t:
- # print(i)
- t1=(i for i in t)
- t2=(i for i in t1)
- print(list(t1))
- print(list(t2))
- >>>[0, 1, 2, 3]
- >>>[]
- 补充:
send()用法,send与next和__next__()都可以使生成器往下执行
yield 2相当于return,控制的是函数的返回值
x=yield的另外一个特性,接收send传过来的值,赋值给x
- # send()用法,send与next和__next__()都可以使生成器往下执行
- # yield 2相当于return,控制的是函数的返回值
- # x=yield的另外一个特性,接收send传过来的值,赋值给x
- def test():
- print('开始第一次')
- first=yield 1
- print('开始第二次',first)
- yield 2
- print('开始第三次')
- yield 3
- t=test()
- print(t.__next__())
- t1=t.send('啊啊啊啊')
- print(t1)
- >>>开始第一次
- 1
- 开始第二次 啊啊啊啊
- 2
生产者消费者模型:
- #两个函数并行:
- #生产者消费者模型
- def consumer(name):
- print('%s准备吃包子了'%(name))
- time.sleep(0.5)
- while True:
- g=yield
- print('%s开始吃%s包子了'%(name,g))
- def producer():
- p1=consumer('alex')
- p1.__next__()
- for i in range(1,10):
- time.sleep(0.5)
- p1.send('第%d'%i)
- producer()
- >>>alex准备吃包子了
- alex开始吃第1包子了
- alex开始吃第2包子了
- alex开始吃第3包子了
- alex开始吃第4包子了
- alex开始吃第5包子了
- alex开始吃第6包子了
- alex开始吃第7包子了
- alex开始吃第8包子了
- alex开始吃第9包子了
python_10 迭代器和生成器的更多相关文章
- Python 从零学起(纯基础) 笔记 之 迭代器、生成器和修饰器
Python的迭代器. 生成器和修饰器 1. 迭代器是访问集合元素的一种方式,从第一个到最后,只许前进不许后退. 优点:不要求事先准备好整个迭代过程中的所有元素,仅仅在迭代到某个元素时才计算该元素,而 ...
- Python之模块,迭代器与生成器
本节涉及内容: 1. 迭代器和生成器 2. 递归 3. 字符串格式化 4. 模块 内置模块 自定义模块 第三方模块 5. 序列化的模块 json pickle (一). 迭代器和生成器: 迭代器: ...
- Python之迭代器和生成器
Python 迭代器和生成器 迭代器 Python中的迭代器为类序列对象(sequence-like objects)提供了一个类序列的接口,迭代器不仅可以对序列对象(string.list.tupl ...
- python学习笔记四 迭代器,生成器,装饰器(基础篇)
迭代器 __iter__方法返回一个迭代器,它是具有__next__方法的对象.在调用__next__方法时,迭代器会返回它的下一个值,若__next__方法调用迭代器 没有值返回,就会引发一个Sto ...
- 【Python】迭代器、生成器、yield单线程异步并发实现详解
转自http://blog.itpub.net/29018063/viewspace-2079767 大家在学习python开发时可能经常对迭代器.生成器.yield关键字用法有所疑惑,在这篇文章将从 ...
- 15.python的for循环与迭代器、生成器
在前面学习讲完while循环之后,现在终于要将for循环这个坑填上了.之所以拖到现在是因为for循环对前面讲过的序列.字典.集合都是有效的,讲完前面的内容再来讲for循环会更加容易上手. 首先,for ...
- Python: 迭代器与生成器小结
迭代器与生成器的区别: 1. 迭代器由Class对象创建. 生成器由包含yield表达的Function对象或者Generator Expression创建. 2. 迭代器的原理: (1)由Itera ...
- Python中的迭代器和生成器
本文以实例详解了python的迭代器与生成器,具体如下所示: 1. 迭代器概述: 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后 ...
- Python可迭代对象、迭代器和生成器
Python可迭代对象.迭代器和生成器 python 函数 表达式 序列 count utf-8 云栖征文 python可迭代对象 python迭代器 python生成器 摘要: 8.1 可迭代对象( ...
随机推荐
- 微信小程序跳转(当我们不知道是普通页面还是tabbar)
页面跳转一般我们都用wx.navigateTo 或者wx.redirectTo等,当页面为tabbar的某一个页面时, 我们盖如何兼容呢我处理的方式为在navigateTo的fail方法中执行wx.s ...
- Xcode 和 VisualC++输出流的差别的理解
将这样一段程序分别运行与Visual Studio 和 Xcode上边的结果: #include <iostream> using namespace std; int main() { ...
- BZOJ - 3170: 松鼠聚会 (切比雪夫转曼哈顿距离)
pro: 有N个小松鼠,它们的家用一个点x,y表示,两个点的距离定义为:点(x,y)和它周围的8个点即上下左右四个点和对角的四个点,距离为1.现在N个松鼠要走到一个松鼠家去,求走过的最短距离.0&l ...
- Python全栈之路----函数进阶----闭包
关于闭包,即函数定义和函数表达式位于另一个函数的函数体内(嵌套函数).而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量.参数.当其中一个这样的内部函数在包含它们之外被调用时,就会形成闭 ...
- 百度地图JS只显示一个省
转载地址:http://www.cnblogs.com/wondergx/p/5305602.html 转载地址:https://blog.csdn.net/myfmyfmyfmyf/article/ ...
- SQLI DUMB SERIES-12
(1)检测闭合方式:在username上输入" admin" " 说明输入的username后还有双引号和括号 方法一: (2)通过其他途径知道用户名即可.如 输入&qu ...
- findHomography(src_points, dst_points, CV_RANSAC)
Homography,即单应性,该函数用于求src_points转换为dst_poinsts的单应性矩阵: 为了理解单应性,必须先引入透视变换的概念:把空间坐标系中的三维物体或对象转变为二维图像表示的 ...
- 在干净的ubuntu 14.10上编译Qemu2.2.0的过程
下载Qemu的源代码 从官网http://wiki.qemu.org/Main_Page 中下载最新的源代码,目前是2.2.0. 安装依赖库和编译 编译过程分两步1. ./configure 2. m ...
- 【转】利用Boost.Python将C++代码封装为Python模块
用Boost.Python将C++代码封装为Python模块 一. 基础篇 借助Boost.Python库可以将C/C++代码方便.快捷地移植到python模块当中,实现对python模块的扩 ...
- ClassNotFoundException与NoClassDefFoundError异常
方法 loadClass()抛出的是 java.lang.ClassNotFoundException异常(一般是jar冲突或者没有引入jar):方法 defineClass()抛出的是 java.l ...