引入:
l = [1,2,3,4,5] s = {1,2,3,4} for i in l: print(i)
如果代码是:
for i in 50: print(i)
这个运行不了。输出结果是 ‘int‘ object is not iterable
iterable是可迭代的意思。
哪些可以迭代呢?这些可以str、list、tuple、set、dic等
可迭代的标志是 _iter_。
那我们如何判断是否可以迭代呢?
print(‘__iter__‘ in dir([1,2,3]))
双下划线的内置方法一般不用这种方法调用:
print(next(l.__iter__()))
而是用这种方法调用:
print(next(iter(l)) )
小结:
(1)可迭代协议——凡是可迭代的内部都有一个__iter__方法
(2)迭代器里既有iter方法,又有next方法 ——迭代器协议
(3)通过iter(o)得到的结果就是一个迭代器
(4)0是可迭代的对象
判断是否是迭代器和可迭代对象的方法:
from collections import Iterable from collections import Iterator s = ‘abc‘ print(isinstance(s,Iterable)) print(isinstance(s,Iterator)) print(isinstance(iter(s),Iterator))
生成器包括两个方面:生成器函数和生成器表达式
生成器有两种:一种是调用方法直接返回的,一种是可迭代对象通过执行iter方法得到的,迭代器有的好处是可以节省内存。
如果在某些情况下,我们也需要节省内存,就只能自己写。我们自己写的这个能实现迭代器功能的东西就叫生成器。
python中内置的生产器:
(1)生成器函数:关键字是yield,yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次继续运行。
(2)生成器表达式:类似于列表推导式,但是返回的是一个对象而不是一个结果列表 ,即惰性运算。
生成器函数:一个含有yield的函数就是生产器函数。通过调用返回的是一个对象,而不是结果列表。通过每一次对这个对象的请求就得到一个值def func(): print(‘aaaa‘)
a=1 yield a#返回第一个值 print(‘bbbbb‘) yield 12#返回第二个值 print(‘cccccc‘) yield 56#返回第三个值 ret=func()#拿到一个生成器 print(next(ret))#取第一个值 print(next(ret))#ret不可以用func替代 print(next(ret))
生成器例子:可以监听一个文本输入的文本
import time def tail(filename): with open(filename) as f: f.seek(0,2) while True: line=f.readline() if not line: #time.sleep() continue yield line for line in tail(‘监视文件‘): print(line,end=‘‘)
可以计算移动平均值的例子:
def averager(): total=0 day=0 average=0 while True: day_num=yield average total+=day_num day+=1 average=total/day avg=averager()#直接返回生成器 next(avg)#激活生成器avg.sed(),什么都 不send和next效果一样 print(avg.send(10)) print(avg.send(15)) print(avg.send(80))
装饰器版计算移动平均值的例子:
def wrapper(func): def inner(*arge,**kwargs): ret=func(*arge,**kwargs) next(ret) return ret return inner @wrapper def averager(): total=0 day=0 average=0 while True: day_num=yield average total+=day_num day+=1 average=total/day avg=averager()#直接返回生成器 # next(avg)#激活生成器avg.sed(),什么都 不send和next效果一样 print(avg.send(10)) print(avg.send(15)) print(avg.send(80))
列表推导式和生成器表达式:
列表推导式:(两个代码实现相同的效果)
for i in range(100): print(i*i) l=[i*i for i in range(100)] print(l)
l = [{‘name‘:‘v‘,‘age‘:28},{‘name‘:‘v‘}] name_list = [dic[‘name‘] for dic in l] print(name_list)
生成器表达式:
l=(i*i for i in range(100)) print(next(l)) print(next(l)) print(next(l)) print(next(l))
l = [{‘name‘:‘v1‘,‘age‘:28},{‘name‘:‘v2‘}] name_list_generator = (dic[‘name‘] for dic in l) #print(name_list_generator) print(next(name_list_generator)) print(next(name_list_generator))
我们会发现列表推导式和生成器表达式除了括号不一样外都一样。列表推导式是中括号,生成器表达式是小括号。
区别:列表推导式是把所有的数据都一起算出来,而生成器表达式是一种惰性运算你请求一次给你一个数据。因此相比较来说生成器表达式更节省内存。
Python不但使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。例如, sum函数是Python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以,我们可以直接这样计算一系列值的和:
print(sum(x**2 for x in range(3)))
而不用多此一举先构造一个列表啦
print(sum([x**2 for x in range(3)]))
总结:
可迭代对象:
拥有_inter_方法
惰性计算
像str、list、tuple、set、dic等
迭代器:
拥有_inter_方法和next方法
像:iter(range()),iter(str),iter(list),iter(tuple),iter(dict),iter(set),reversed(list_o),map(func,list_o),filter(func,list_o),file_o
特点: 可以用for循环、 可以节省内存、只能用一次
生成器:本质是迭代器(同时拥有_inter_和next方法)
是开发人员自己定义的迭代器
优点:
1.延迟计算,你请求一次他给你返回一个结果。他不会给你返回所有的结果,不会大量占据内存
2.代码简洁,容易读