python3.x 基础四:生成器与迭代器
1.预先存值到内存,调用之前已经占用了内存,不管用与不用,都占用内存
>>> a=[1,2,3,4,5] >>> type(a) <class 'list'> >>> len(a) 5 >>> a = [ i for i in range(1,6)] #列表生成式,这里的i可以是一个函数 >>> type(a) <class 'list'> >>> len(a) 5 >>> a [1, 2, 3, 4, 5] >>> a=[] >>> for i in range(10): ... a.append(i) ... >>> a [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
2.generateor 一边循环一边计算的机制,节省空间,只有在调用的时候才会生成对应的数据,可以用next访问
将列表生成式的中括号改成小括号,就变成生成器了
>>> [ i for i in range(1,6)] [1, 2, 3, 4, 5] >>> (i for i in range(1,6)) <generator object <genexpr> at 0x7f8747a69678> >>> a=(i for i in range(1,6)) >>> type(a) <class 'generator'> >>> a.__next__() 1 >>> a.__next__() 2 >>> a.__next__() 3 >>> a.__next__() 4 >>> a.__next__() 5 >>> a.__next__() Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
3.斐波那契
def fib(max): n,a,b=0,0,1 while n<max: print(b) a,b=b,a+b n=n+1 return 'done' fib(10)
4.将上面的print(b)改成生成式关键字 yield,就是生成器了
def fib(max): n,a,b=0,0,1 while n<max: yield b a,b=b,a+b n=n+1 return 'done' gen=fib(10) print(type(gen))
5.每次调用生成器的时候,遇到yield则返回本次值,然后跳出生成器,可执行其他指令,在下一次调用生成器的时候,将从上次结束的地方开始运行,直到yield跳出
def fib(max): n,a,b=0,0,1 while n<max: yield b a,b=b,a+b n=n+1 return 'done111' gen=fib(5) print(type(gen)) print(next(gen)) print('小明滚进来') print(next(gen)) print('小明滚出去') print(next(gen)) print('小明滚进来') print(next(gen)) print('小明滚出去') print(next(gen))
输出结果:
<class 'generator'>
1
小明滚进来
1
小明滚出去
2
小明滚进来
3
小明滚出去
5
6.处理异常try:处理内容 except:内容异常处理
def fib(max): n,a,b=0,0,1 while n<max: yield b a,b=b,a+b n=n+1 return 'done111' gen=fib(5) print(type(gen)) while True: try: val=next(gen) print('fib value is',val) except StopIteration as e: print(e.value) break <class 'generator'> fib value is 1 fib value is 1 fib value is 2 fib value is 3 fib value is 5 done111
7.生产者与消费者
- g.__next__遇到yield返回,下一次从yield开始,但是不会赋值
- g.send()遇到yield唤醒迭代器,赋值
- 进程-线程-携程,epoll异步IO原理
- epoll是Linux内核为处理大批量文件描述符而作了改进的poll,是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。另一点原因就是获取事件的时候,它无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件异步唤醒而加入Ready队列的描述符集合就行了
#/usr/bin/env python #-*- coding: utf-8 -*- #Author:jenvid.yang import time def consumer(name): print('%s is ready to have baozi!' %(name)) while True: baozi = yield print('baozi %s is coming,baozi was ate by %s' %(baozi,name)) c=consumer('alex') # c.__next__() # b1='baozi001' # c.send(b1) def producer(): c1=consumer('oldboy') c2=consumer('alex') c1.__next__() c2.__next__() print('i am going to make baozi!') for i in ['韭菜馅','猪肉馅','白菜陷','玉米馅','萝卜馅']: time.sleep(1) print('finish 2 baozi') c1.send(i) c2.send(i) producer()
8.迭代器
- 列表/元组/字典/集合/字符串/生成器,可以用于for循环的对象统称为可迭代对象:Iterable
- isinstance(),判断一个一个对象是否是Iterable对象
-
>>> from collections import Iterable >>> isinstance([],Iterable) True >>> isinstance('123',Iterable) True >>> isinstance({},Iterable) True >>> isinstance((),Iterable) True
- 能用next()函数调用并返回下一个值的对象成为迭代器,Iterator
-
>>> from collections import Iterator >>> isinstance([],Iterator) False >>> isinstance('123',Iterator) False >>> isinstance((),Iterator) False >>> isinstance((i for i in range(2)),Iterator) True
- 生成器是迭代器Iterator,但是Iterable不一定是Iterator,用iter()函数可以将迭代类型转成迭代器
-
>>> isinstance('123',Iterator) False >>> isinstance(iter('123'),Iterator) True
- 迭代:
- 迭代器不能预先知道循环的长度
- 只能通过next()取下一个
- 最后结果抛出StopIterator错误
- 可for循环取值的对象是可迭代类型Iterable
- 可next()取值的对象是迭代器Iterator