一、列表生成式
>>> [ 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