了解生成器
我们知道迭代器有两种:一种是调用方法直接放回的;一种是可迭代对象执行iter方法得到的。迭代器的有点是可以节省内存。
如果在某些情况下,我们也需要节省内存,就只能是自己写,我们自己写的这个能实现迭代器功能的东西就叫做生成器。
- python中提供的生成器
- 生成器的函数:常规函数定义,但是,使用的是yield语句而不是return语句返回结果,yield语句一次返回一个结果,在每个结果中间,挂起函数状态,以便在下次从它离开的地方继续执行,返回结果。
- 生成器的表达式:类似于列表推导,但是返回的是一个按需产生的一个对象,而不是一个结果列表。
- 生成器
- 本质:迭代器
- 特点:惰性运算,开发者自定义
生成器函数
一个包含yield关键字的函数就是生成器函数,yield可以为我们从函数中返回值,但是yield不同于return,return的执行意味着程序的结束。调用生成器函数不会得到返回具体的值,而是得到一个迭代对象,每一次获取这个可迭代对象的值,就能够推动函数的执行,获取新的函数值,知道函数执行结束。
def genrator_func():
x = 1
print("定义了一个变量x")
yield x
y = 2
print("定义了一个变量y")
yield y
ret = genrator_func()
print(ret) //<generator object genrator_func at 0x000002F8BE620750>
for i in ret:
print(i)
从执行的结果来看,直接打印执行生成器返回的结果是一个 genrator
那么生成器有什么优点呢?就是在内存中不会产生太多的数据,当yield进行了返回,执行下一个yield时,那么前面一个yield的值就会从内存中进行清除,总之,就是需要值的时候就会从生成器中去获取
这里举个例子:假如我要一批零件,需要找工厂进行加工,需要20000000个,跟工厂沟通好了之后工程再去生产,我可以一个一个的要,可以一批一批的要,而不是说我要20000000个,工厂就先将20000000个先加工好,然后在一次性去取回来
def production():
for i in range(20000000):
yield "加工的第 %s 个零件"%i
ret = production()
print(ret.__next__()) //可以一个一个的取
print(ret.__next__())
for x in ret:
print(x)
生成器的应用
- 从文件中读取数据
def tail(filename): f = open(filename) while True: line = f.readline() // 从文件中读取新的文件行 if line.strip(): yield line.strip() tail_f = tail("tmp") for line in tail_f: print(line)
- 读取文件时,next和send的比较
send 获取下一个值的效果和next效果是一样的def generator(): print(123) content = yield 1 print('=======',content) print(456) yield 2 g = generator() ret = g.__next__() print('***',ret) ret = g.send('hello') //send的效果和next一样 print('***',ret)
只是在获取下一个值的时候,给上一个yield的位置传递一个数据
在使用send时应该注意的事项:- 第一次使用生成器的时候,使用next去获取下一个值
- 最后一个yield不能够传递值
- 计算移动平均值
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 averager_g = averager() // averager_g.__next__() // 将这一步提到装饰器中,在装饰器中进行执行 print(averager_g.send(5)) print(averager_g.send(15)) print(averager_g.send(20)) print(averager_g.send(30))
小结
- 可迭代对象
拥有__iter__方法
特点:惰性运算
例如:range(),str,list,tulp,set - 迭代器Iterator
拥有__iter__和__next__方法 - 生成器
本质:迭代器,拥有__iter__和__next__方法
特点:惰性运算,开发者自定义 - 使用生成器的优点
延迟计算,一次返回一个结果,也就是说,不会一次性生成所有的结果,这对于大数据量处理,将会非常有用
提高代码可读性