列表生成式,迭代器&生成器
列表生成式
[1, 2, 3, 4, 5, 6, 7, 8, 9],把列表里的每个值乘2
第一种方法
a = [1,2,3,4,5,6,7,8,9]
for index,i in enumerate(a):
a[index] *=2
print(a)
第三种
a = [1,2,3,4,5,6,7,8,9]
a = map(lambda x:x*2, a)
<map object at 0x101d2c630>
for i in a:print(i)
第四种
a = [1,2,3,4,5,6,7,8,9]
a = [i*2 for i in range(10)] >>>[2,4,6,8,10,12,14,16,18]
这就叫做列表生成
生成器
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含上亿个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]
改成()
,就创建了一个generator:
a = (x*2 for x in range(10))
a就是一个生成器对象 且可迭代
<generator object foo at 0x0000016D83F16A40>
打印出generator的每一个元素 如果要一个一个打印出来,可以通过next()
函数获得generator的下一个返回值
next(a)>>2
next(a)>>4
next(a)>>6
next(a)>>8
next(a)>>10
next(a)>>12
next(a)>>14
next(a)>>16
next(a)>>18
generator保存的是算法,每次调用next(a)
,就计算出g
的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration
的错误。
正确的方法是使用for
循环,因为generator也是可迭代对象:
a = (x*2 for x in range(10)
for i in a:
print(i)
我们创建了一个generator后,基本上永远不会调用next()
,而是通过for
循环来迭代它,并且不需要关心StopIteration
的错误。
斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:
def fib(max):
n ,before,after = 0,0,1
while n<max:
print(before)
before,after = after ,before+after
n+=1
fib(10)
上面的函数和generator仅一步之遥。要把fib
函数变成generator,只需要把print(b)
改为yield b
就可以了:
def fib(max):
n ,before,after = 0,0,1
while n<max:
# print(before)
yield before #生成器next方法
before,after = after ,before+after
n+=1
# fib(10)
g = fib(8)
print(g)
print(next(g))
for i in g:
print(i)
迭代器
每一个生成器都是迭代器 迭代器不一定是生成器
以直接作用于for
循环的数据类型有以下几种:
一类是集合数据类型,如list
、tuple
、dict
、set
、str
等;
一类是generator
,包括生成器和带yield
的generator function。
这些可以直接作用于for
循环的对象统称为可迭代对象:Iterable
。
有iter()方法和next()方法才叫迭代器
for i in [1,3,4,5]
for循环内部三件事:
调用可迭代对象的iter方法返回一个迭代器
不断调用迭代器next方法
处理StopIteration
错误
可以使用isinstance()
判断一个对象是否是Iterable
对象:
from collections import Iterable,Iterator
b = [1,2,3,4]
a = isinstance(b,list)
print(a)
b =iter(b)
print(isinstance(b,Iterator))
>>TRUE TRUE
凡是可作用于for
循环的对象都是Iterable
类型;
凡是可作用于next()
函数的对象都是Iterator
类型,它们表示一个惰性计算的序列;
集合数据类型如list
、dict
、str
等是Iterable
但不是Iterator
,不过可以通过iter()
函数获得一个Iterator
对象。