1.先了解下列表生成式
有一个列表[1,2,3,4,5,6,7,8,9],对没一个元素都进行*2
#通用做法是用lamba
ret = map(lambda x:x*2,[1,2,3,4,5,6,7,8,9])#python3 得到的ret 是一个map对象,在通过for循环得到#python2 得到的事一个列表不需要再次for循环
print(ret) #
for i inret:print(i)#通过列表生成式直接生成一个列表
ret = [x*2 for x in [1,2,3,4,5,6,7,8,9]]
2.什么是生成器?
通过列表生成式,我们可以直接创建一个列表,但是,受到内存限制,列表容量肯定是有限的,而且创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,就会浪费大量的内存空间。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间,在Python中,这种一边循环一边计算的机制,称为生成器:generator
生成器是一个特殊的程序,可以被用作控制循环的迭代行为,python中生成器是迭代器的一种,使用yield返回值函数,每次调用yield会暂停,而可以使用next()函数和send()函数恢复生成器。
3.python中的生成器,生成器表达式:返回一个对象,这个对象只有在需要的时候才产生结果
#要创建一个generator,有很多种方法,第一种方法很简单,只有把一个列表生成式的[]中括号改为()小括号,就创建一个generator
#列表生成式
lis = [x*x for x in range(10)]print(lis)#生成器
generator_ex = (x*x for x in range(10))print(generator_ex)
结果:
[0,1, 4, 9, 16, 25, 36, 49, 64, 81] at 0x000002A4CBF9EBA0>
#得到的结果也不一样,一个是列表一个是对象,那么如何打印出generator_ex的每一个元素呢?通过generator_ex.__next__()或者next(generator_ex)
结果:
01
4
9
16
25
36
49
64
81Traceback (most recent call last):
File"列表生成式.py", line 42, in
print(next(generator_ex))
StopIteration#到最后一个元素后,再次调用__next__() 会触发 StopIteration error,代表已经没有元素了,这种感觉很不好,所以一般我们使用for 循环拿就不会触发error,因为generator也是可迭代对象
for i ingenerator_ex:print(i)
3.生成器函数使用以斐波那切数列举例,从第3项开始,每一项都等于前两项之和。1 1 2 3 5 8 13 21 34......
生成器函数:也是用def定义的,利用关键字yield一次性返回一个结果,阻塞,重新开始
#斐波那契数列,普通函数形式
deffib(number):
n=0
a,b=0,1
while n
a,b=b,a+b
n=n+1
print(a)return ('done')
a= fib(10)print(a)#通过生成器实现,每次调用__next__() 都会yield d 拿到b 这个值,然后继续循环到yiled b停住,继续监听有没有next调用
deffib(number):
n=0
a,b=0,1
while n
a,b=b,a+b
n=n+1
return('done')
f=fib(3)#通过for循环拿不到return值
for i inf:print(i)#结果:
1
1
2
3
5
8
13
21
34
55
#要是想得到return 返回值就需要__next__()通过try except获取异常
deffib(number):
n,a,b=0,0,1
while n
a,b=b,a+b
n= n+1
return('done')
g= fib(6)whileTrue:try:
x= __next__(g)print('generator:',x)exceptStopIteration as e:print("生成器返回值:",e.value)break结果:
generator:1generator:1generator:2generator:3generator:5generator:8生成器返回值: done
4. 生成器 send 用法
defgenerator():whileTrue:
receive= yield 1
print('hahaha' +str(receive))yield 2g=generator()print(next(g)) #一定要先next一次后再send值,不然会报错
print(g.send('ok')) #send ok 给receive接收,receive = yield 1 这句就代表结束了,然后遇到下一次的yiled断点 返回yiled的值#print(next(g))
#结果:
1hahaha ok2
1
5.通过 generator yiled 来实现协程,标准的生产者-消费者模型
importtimedefconsumer():
r= ''
whileTrue:
r= '我饿了'n= yield r #这个n 是生产者发送过来的n 不是r 这个值
print(n)if notn:return
print('[消费者] 消费了 %s 个大包子...' %n)#time.sleep(1)
#c = consumer()#print(c.__next__())#print(c.send('a'))
defproduce(c):#消费者调用next 准备send包子
print(c.__next__())
n=0#设定生产几个包子
while n < 5:
n= n + 1
print('[生产者] 生产了 %s 个大包子...' %n)
r= c.send(n) #send给 消费者 并且接收了yiled '我饿了'
if r == '我饿了':print('[生产者] 消费者说真他妈好吃啊')else:print('[生产者] 消费者说狗都不想吃')
c.close()if __name__=='__main__':
c= consumer() #消费者实例
produce(c)#结果:
我饿了
[生产者] 生产了1个大包子...
[消费者] 消费了1个大包子...
[生产者] 消费者说真他妈好吃啊
[生产者] 生产了2个大包子...
[消费者] 消费了2个大包子...
[生产者] 消费者说真他妈好吃啊
[生产者] 生产了3个大包子...
[消费者] 消费了3个大包子...
[生产者] 消费者说真他妈好吃啊
[生产者] 生产了4个大包子...
[消费者] 消费了4个大包子...
[生产者] 消费者说真他妈好吃啊
[生产者] 生产了5个大包子...
[消费者] 消费了5个大包子...
[生产者] 消费者说真他妈好吃啊
6.迭代器
迭代器就是循环,并且可以用next调用
可迭代对象Iterable不一定是Iterator迭代器,但是迭代器一定时可迭代对象。
生成器都是迭代器Iterator,但list、dict、str虽然是Iterable(可迭代对象),却不是Iterator(迭代器),可以使用for 循环的都是可迭代对象。
#判断是否为可迭代对象
>>> from collections importIterable>>>isinstance([], Iterable)
True>>>isinstance({}, Iterable)
True>>> isinstance('abc', Iterable)
True>>> isinstance((x for x in range(10)), Iterable)
True>>> isinstance(100, Iterable)
False#也可以使用isinstance()判断一个对象是否是迭代器Iterator对象:
>>> from collections importIterator>>> isinstance((x for x in range(10)), Iterator)
True>>>isinstance([], Iterator)
False>>>isinstance({}, Iterator)
False>>> isinstance('abc', Iterator)
False#可以使用iter()变成迭代器对象
>>>isinstance(iter([]), Iterator)
True>>> isinstance(iter('abc'), Iterator)
True>>> a=[1,2,3,4]>>> b=iter(a)>>> print(b)
>>> b.__next__()1
>>> b.__next__()2
>>> b.__next__()3
>>> b.__next__()#要判断一个对象是不是迭代器 可以直接用next方法调用,或者用isinstance(对象,Iterator)