{i:el for i,el in enumerate(["one","two","three"])}
{0: 'one', 1: 'two', 2: 'three'}
enumerate()
是内建函数,可以让列表获得“下标”的属性。
而如果不用列表推导式,上例需要这么写:
lst = ["one","two","three"]
i = 0
for e in lst:
lst[i] = '%d: %s' % (i,lst[i])
i +=1
lst
['0: one', '1: two', '2: three']
import sys
i = iter(range(10000))
id(i.__next__())
93933276092968
sys.getsizeof(i)
40
sys.getsizeof(i.__next__())
28
e = range(10000)
sys.getsizeof(e)
48
sys.getsizeof(list(e))
80056
可以看到,如果一次性把 list
全部加载进来,需要 90112byte
内存空间,
如果使用迭代器迭代,仅仅需要 28byte
内存空间。
可以被 next()
函数调用并不断返回下一个值的对象称为迭代器。
生成器都是 Iterator
对象,但 list
、 dict
、 str
虽然是 Iterable
,却不是 Iterator
,
list
, tuple
, dict
, str
是有可迭代属性(惰性循环),但如果需要转化成可迭代对象,
可以用 iter()
来转换,验证方式就是看对象是否有__next__
方法。
生成器(generator)
生成器是一种特殊的迭代器。
什么时候需要用生成器
其实一般情况下是不需要生成器的,只有当因为性能限制下才需要用到,
比如需要用python来 read
一个10g的 txt
文件,如果一次性把10g的文件加载到内存再处理( .read()
方法),
内存肯定溢出了。这里如果使用生成器,就可以把读和处理交叉进行,
比如使用( .readline
和 .readlines
)就可以在循环读取的同时不断处理,这样可以节省大量内存空间。
此外,还可以使用生成器生成线程池。
(如果当自己写一个读写函数封装给别人使用时,那么要考虑到文件容量问题,此时应该考虑使用生成器。)
生成生成器的两种方法
第一种比较简单,将列表推导式的 []
改称 ()
就可以了:
g = (x*x for x in range(10))
'__next__' in dir(g)
True
在这里可以看到g有一个__next__
的魔术方法,而这是生成器所特有的属性,下面两种方式调用都可以。
g.__next__()
0
g.__next__()
1
next(g)
4