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 可迭代对象( ...
随机推荐
- Spring中的@Bean注解、@Configuration注解、@Value
1.首先是注册bean类:@Component.@Responsitory.@Controller.@Service.Configuration这些注解是把要实例化的对象装化成一个bean,放到Ioc ...
- c程序的期望
对于C语言,我认为是我们计算机专业必须掌握的,如果C语言都不能掌握好,我认为在以后的学习中也不会学的有多好,所以,我们要把C语言尽量掌握好,也是在今后的学习中打好基础,多看书,多写一些程序运行,做一些 ...
- python 的排名,已经python的简单介绍
我在今天看了一篇文章,是简书的全网程序猿写的,Java已经退出神坛,python稳居第一. python是由龟叔写的,它在英文的意思是蟒蛇. 根据编程语言流行指数排行榜2019年2月的榜单 据了解,目 ...
- ES5与ES6中的继承
ES5继承在ES5中没有类的概念,所以一般都是基于原型链继承,具体的继承方法有以下几种: 父类: function Father (name) { this.name = name || 'sam' ...
- 洛谷P1219 :八皇后(DFS+回溯)
题目描述 检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行.每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子. 上面的布局可以用序列2 4 6 1 3 ...
- Hello2 分析
一.打开GreetingServlet.java文件以查看它 hello2应用程序是一个web模块,hello2应用程序的行为几乎与hello1应用程序相同,但是它是使用Java Servlet技术实 ...
- 关于ava容器、队列,知识点总结
推荐<java 并发编程实战>这本书,中文的翻译有些差(哈哈,并发确实难,不好翻译),适合有并发经验的人来读. 这篇短文,整理了容器的知识点,对容器的使用场景,容器的原理等有个整体的认知! ...
- ARTIFICIAL INTELLIGENCE FOR GAMES (Ian Millington / John Funge 著)
相关网站:http://www.ai4g.com PART I AI AND GAMESCHAPTER1 INTRODUCTIONCHAPTER2 GAME AIPART II TECHNIQUESC ...
- Python调用ffpmeg和ffprobe处理视频文件
需求: 运营有若干批次的视频.有上千个,视频文件,有mp4格式的,有ts格式的 现在有需要去掉视频文件片头和片尾的批量操作需求. 比如 文件夹A下面的视频去掉片尾10秒 文件夹B下面的视频去掉片头6秒 ...
- 3.3-1933 problem A
#include <stdio.h> int main(void){ int h; while(scanf("%d", &h) != EOF){ * (h-); ...