迭代器和生成器
1、什么是迭代器和可迭代对象
(1) 可迭代对象
定义:内部实现了__iter__方法,即可迭代协议。可迭代协议的定义非常简单,可以被迭代要满足的要求就叫做可迭代协议。
(2)迭代器
定义:迭代器遵循迭代器协议:必须拥有__iter__方法和__next__方法。
补充:迭代器是python内置的,如果一个对象是可迭代的但不一定是迭代器。
迭代器有两种:一种是调用方法直接返回的,一种是可迭代对象通过执行iter方法得到的,迭代器有的好处是可以节省内存。
举例:
print('__next__' in dir(range(12))) #查看'__next__'是不是在range()方法执行之后内部是否有__next__ print('__iter__' in dir(range(12))) #查看'__next__'是不是在range()方法执行之后内部是否有__next__ from collections import Iterator print(isinstance(range(100000000),Iterator)) #验证range
2、初识生成器
定义:我们自己写的这个能实现迭代器功能的东西就叫生成器。
(1)python中提供的生成器
1、生成器函数
特点:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行。
2、生成器表达式
特点:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表。
(2)生成器generator
本质:迭代器(所以自带了__iter__方法和__next__方法,不需要我们去实现)
特点:惰性运算,开发者自定义。
3、生成器函数
(1)定义:一个包含yield关键字的函数就是一个生成器函数。yield可以为我们从函数中返回值,但是yield又不同于return,return的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,而是得到一个可迭代的对象。每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值。直到函数执行结束。
import time def genrator_fun1(): a = 1 print('现在定义了a变量') yield a b = 2 print('现在又定义了b变量') yield b g1 = genrator_fun1() print('g1 : ',g1) #打印g1可以发现g1就是一个生成器 print('-'*20) #我是华丽的分割线 print(next(g1)) time.sleep(1) #sleep一秒看清执行过程 print(next(g1))
(2)生成器的应用
1、监听文件
import time def tail(filename): f = open(filename) f.seek(0, 2) #从文件末尾算起 while True: line = f.readline() # 读取文件中新的文本行 if not line: time.sleep(0.1) continue yield line tail_g = tail('tmp') for line in tail_g: print(line
2、计算移动平均值
def init(func): #在调用被装饰生成器函数的时候首先用next激活生成器 def inner(*args,**kwargs): g = func(*args,**kwargs) next(g) return g return inner @init def averager(): total = 0.0 count = 0 average = None while True: term = yield average total += term count += 1 average = total/count g_avg = averager() # next(g_avg) 在装饰器中执行了next方法 print(g_avg.send(10)) print(g_avg.send(30)) print(g_avg.send(5))
3、yield from的应用
def gen1(): for c in 'AB': yield c for i in range(3): yield i print(list(gen1())) def gen2(): yield from 'AB' yield from range(3) print(list(gen2()))
4、列表推导式和生成器表达式
列表推导式
print([i for i in range(10) if i%2==1])
生成器表达式
print((i for i in range(10) if i%2==1))
总结:1、列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存。
2、列表解析式返回的是一个结果,而生成器表达式返回的是一个生成器。
使用生成器的优点:
1.延迟计算,一次返回一个结果
2.、提高代码可读性