Day6 python基础6 迭代器和生成器
一、列表生成式
>>> [ i*2 for i in range(10)] [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
这一句话就相当于
>>> a = [] >>> for i in range(10): ... a.append(i*2) ... >>> a [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
二、生成器
通过列表生成式可以直接创建一个列表,在创建的过程中就会一次生成列表中的所有元素,当列表太大时就会占用过大的空间。
python中,存在一种边循环边计算的机制,称为生成器generator。
创建生成器的第一种方法:
>>> l = [ i*2 for i in range(10)] >>> l [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] >>> g = ( i*2 for i in range(10)) #生成器 >>> g <generator object <genexpr> at 0x0000029B1714C1A8>
创建生成器与列表生成式的区别在于最外层的[]和()。
生成器的值只能通过next()方法从头到尾一个一个获得,每调用一次next(g),就计算一个g的值,直到计算的最后一个值,没有更多元素时抛出StopIteration异常。
>>> next(g) 0 >>> next(g) 2 >>> next(g) 4 >>> next(g) 6 >>> next(g) 8 >>> next(g) 10 >>> next(g) 12 >>> next(g) 14 >>> next(g) 16 >>> next(g) 18 >>> next(g) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
也可以通过for循环来得到g的值,因为生成器也是可迭代对象。
>>> g = (2*i for i in range(10)) >>> for n in g: ... print(n) ... 0 2 4 6 8 10 12 14 16 18
创建生成器的第二种方法,yield关键字。
示例:斐波那契数列(Fibonacci),除第一个和第二个数外,每一个数都为前两个输之和:
1,1,2,3,5,8,13,21,34,...
斐波那契数列无法用列表生成式的形式写出,但可以用函数的形式写出
1 def fib(max): 2 n,a,b = 0,0,1 3 while n<max: 4 print(b) 5 a,b = b,a+b #相当于t=(b,a+b);a=t[0];b=t[1] 6 n+=1 7 8 fib(10)
1 1 2 3 5 8 13 21 34 55
fib函数也是从第一个元素开始,逐个算出后续的元素,若把 print(b) 改为 yield b ,就变成了生成器。
>>> def fib(max): ... n,a,b = 0,0,1 ... while n<max: ... yield b ... a,b = b,a+b ... n=n+1 ... return 'done' ... >>> f = fib(6) >>> f <generator object fib at 0x0000029B1714C1A8> >>> f.__next__() 1 >>> f.__next__() 1 >>> f.__next__() 2 >>> f.__next__() 3 >>> f.__next__() 5 >>> print("do something else") do something else >>> f.__next__() 8 >>> f.__next__() Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration: done >>>
在生成器运行过程中,每遇到一次yield,函数会暂停并保留当前所有的运行信息,返回yield,并在下一次执行next()方法时从当前位置继续执行。
若想得到generator的return语句的返回值,需捕获StopIteration错误。
>>> g = fib(6) >>> while True: ... try : ... x = next(g) ... print(x) ... except StopIteration as e: ... print("generator return:",e.value) ... break ... 1 1 2 3 5 8 generator return: done
三、迭代器
迭代是访问集合元素的一种方式,迭代器对象从集合的第一个元素开始访问,直到被所有元素访问完结束。迭代器只能前进不能后退,且只能从头到尾依次访问。
迭代器不需要事先生成整个迭代过程中所需的所有元素,而是在迭代到该元素时才生成该元素,而在这之前或之后,元素可以不存在。这一特点使其适合用于遍历一些巨大的或无限的集合。
迭代器有两个基本方法:next()和iter(),分别用于遍历和生成迭代器。
可以用于for循环的数据类型有以下几种:
一类是集合数据类型,如list、tuple、dict、set、str等;
一类是generator,包括生成器和带yield的generator function。
这些可以直接作用于for循环的对象统称为可迭代对象:Interable。
可以使用isinstance()判断一个对象是否是Iterable对象:
>>> from collections import Iterable >>> isinstance([],Iterable) True >>> isinstance({},Iterable) True >>> isinstance('abc',Iterable) True >>> isinstance((i*2 for i in range(10)),Iterable) True >>> isinstance(100,Iterable) False
生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration异常。
可被next()函数调用并不断返回下一个值的对象称为迭代器Iterator。
可以使用isinstance()判断一个对象是否是Iterator对象:
>>> isinstance(100,Iterable) False >>> from collections import Iterator >>> isinstance((i for i in range(10)),Iterator) True >>> isinstance([],Iterator) False >>> isinstance({},Iterator) False >>> isinstance('abc',Iterator) False
Interator一定是Interable,但Intearble不一定是Iterator。
python中的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration
错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator
的计算是惰性的,只有在需要返回下一个数据时它才会计算,而list,dict,str等是直接产生所有数据,故list,dict,str这些数据类型不是Iterator。
但可以通过iter()方法把list,dict,str等变为Iterator。
>>> isinstance(iter('abc'),Iterator) True >>> isinstance(iter([]),Iterator) True
python中的for循环的本质就是通过不断调用next()方法实现的,例如:
for x in [1,2,3,4,5]: pass
就相当于:
it = iter([1,2,3,4,5]) while True: try: x = next(it) except StopItreation: break