生成器攻略 列表推导式和生成器表达式
你第一次看到生成器的样子so beautiful !!!
首先 我们学习的迭代器有两种:
1. 调用方法直接返回。 map 和 fileter (这个我最开始看到也蒙了, 上一篇没有写啊,
于是我问了老师和同学, 暂且先把这个东西就这样记。)
2。 可迭代对象通过执行 iter 方法得到。
我们写的能实现迭代器功能的东西就叫做生成器。
python 中给我们提供的有生成器:
1:生成器函数:和正常函数定义一样,但是,but but but 生成器是使用 yield 语句而不是 return 语句返回结果。yield 语句一次只返回一个结果,在每个结果中间,挂起函数的状态,以便下次从它离开的地方继续执行
2: 生成器表达式: 类似于列表推导(列表推导什么鬼。。。),but but but ,生成器返回按需求产生结果的一个对象,而不是一次构建一个结果列表。 我自己理解的最后这句话意思就是,这个表达式每次只返回一个值, 你要一个我给你一个, 你不要就不要 我也不会硬塞给你。
生成器Generatol (顺便回顾下迭代器 iterator 和可迭代的 iterable )
本质:迭代器(因为自带了__iter__ 和__next__方法,所以不需要我们去实现
特点: 惰性运算,开发者自定义(开发者自定义什么鬼)
生成器函数:
一个包含了 yield 关键字的函数就是一个生成器函数。yield 可以为我们从函数中返回值。
yield 和 return 的区别:
return 的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,而是得到一个可迭代的对象。 y
ield每一次获取这个可迭代对象的一个值,就能推动函数的执行,获取新的返回值,直到函数执行结束。
来,操练起来。
#先定义函数
import time
def genrator_fun():
a = 3
print('现在定义了变量 a')
yield a
n = a
print(n)
b = 2
print(' 现在定义了变量 b')
yield b
g1 = genrator_fun()
print('g1:',g1)# 这个 print 是看这个 g1 是什么鬼
print('='*20)
print(next(g1))
time.sleep(1)
print(next(g1))
====================
现在定义了变量 a
3
3
现在定义了变量 b
2
生成器的好处: 不会一下子在内存中生成太多数据。
继续认识生成器:
假如我想让工厂给学生做校服,生产2000000件衣服,我和工厂一说,工厂应该是先答应下来,然后再去生产,我可以一件一件的要,也可以根据学生一批一批的找工厂拿。
而不能是一说要生产2000000件衣服,工厂就先去做生产2000000件衣服,等回来做好了,学生都毕业了。。。
def produce():
'''生产衣服'''
for i in range(2000000):
yield('生产了第%s件衣服'%i)
produce_g = produce()
print(produce_g.__next__())#要第一件衣服
print(produce_g.__next__())#要第二件衣服
print(produce_g.__next__())#要第三件衣服
print(produce_g.__next__())#要第四件衣服
num = 0
for i in produce_g:
print(i)
num+=1
if num ==5 :
break
#到这里我们找工厂拿了8件衣服, 对 是8件,上面三件 下面那个 for i in 那拿了五件,一共八件
我一共让我的生产函数(也就是produce生成器函数)生产2000000件衣服。
剩下的还有2000000-8件衣服,现在情况就是, 我要了你给我, 我不要 你就给我留那,
我什么时候要,你就什么时候立马给,完全服从。
对,就像你和你女朋友的关系。 你懂得。
#生成器监听文件输入的例子
import time
def tail(filename):
f = open(filename)
f.seek(0,2)#从文件末尾算起
while 1 :
line = f.readline()#读取文件中新的文本行
if not line:
time.sleep(0.5)
continue
yield line
tail_g = tail('tmp')
for line in tail_g:
print(line)
#计算移动平均值
def averager():
count =0
total = 0
averager = None
while True:
term = yield averager
total +=term
count+=1
averager = total / count
g_avg = averager()
next(g_avg)
print(g_avg.send(10))
print(g_avg.send(7))
print(g_avg.send(17))
#计算移动的平均值(2) 预激协程的装饰器
def init(func): #在调用被装饰生成器函数的时候首先用 next 激活生成器
def inner(*args,**kwargs):
g = func(*args,**kwargs)
next(g)
return inner
@init
def averager ():
total = 0
count = 0
averager = None
while True:
term = yield averager
total +=term
count +=1
averager = total / count
g_avg = averager()
#next(g_avg) # 在装饰器中执行了 next 方法
print(g_avg.send(666))
print(g_avg.send(777))
print(g_avg.send(888))
'''
导入 time 模块
定义函数(要传参数)
打开文件 f = open
f.seek(0,2) 从文件的末尾开始算
while 1 : while 循环
if not line:(如果读不到)
如果读不到就睡一会
continue 跳过本层
yield line (返回 line, 并把步骤停在这步)
tail_g = tail()
for line in tail_g:
print(line)
列表推导式和生成器表达式
和列表一样,列表推导式也采用方括号[]表示,并且用到了一个简写版的for循环,第一部分是一个生成结果列表元素的表达式,
第二部分是一个输入表达式上的循环。阅读理解列表表达式的推荐做法是先从里面的for循环开始,
向右查看是否有if条件,然后将推导式开始的那个表达式映射到每一个匹配的元素上去。
列表推导式:用[]表示
even_numbers = [x for x in range(10) if x % 2 ==0]
:[0,2,4,6,8]
python还支持另外一种和表列表达式类似的结构,
叫做生成器表达式(generator expression)
它的优点: 1.惰性计算
2.节省内存
even_numbers = (x for x in range(10) if x%2 ==0)
print(list(even_numbers))
# [0, 2, 4, 6, 8]
在处理大量的数据是,最好考虑生成器表达式而不是列表推导式。
另一个列表推导式和生成器表达式的例子是:
- >>> data = ['abc','def','I use python', 'f123']
- >>> sum([len(word) for word in data])
- 25
- >>> sum(len(word) for word in data)
- 25
enumerate()是一个同时能让你迭代和计数的内置函数,
而for循环自身只能迭代而没办法计数:
- >>> data = [123,"abc",3.14]
- >>> for i in enumerate(data):
- ... print i
- ...
- (0, 123)
- (1, 'abc')
- (2, 3.14)
#老男孩由于峰哥的强势加盟很快走上了上市之路,alex思来想去决定下几个鸡蛋来报答峰哥 egg_list=['鸡蛋%s' %i for i in range(10)] #列表解析 #峰哥瞅着alex下的一筐鸡蛋,捂住了鼻子,说了句:哥,你还是给我只母鸡吧,我自己回家下 laomuji=('鸡蛋%s' %i for i in range(10))#生成器表达式 print(laomuji) print(next(laomuji)) #next本质就是调用__next__ print(laomuji.__next__()) print(next(laomuji))