生成器与迭代器
生成器与迭代器 |
一、生成器
1.列表推导式
列表推导式是Python内置的非常简单且强大的可以用来轻松创建列表的方法。它可以使用非常简单的语句利用其他列表创建新的列表。
例如,创建1到10的所有偶数的平方的列表:
list = [i*i for i in range(1,11) if i%2==0] print(list) #结果为:[4, 16, 36, 64, 100]
列表推导式的书写规则是,生成的元素放在语句前面,紧跟着的是for循环。
2.生成器表达式
列表一旦被创建,其包含的元素就实实在在地存在内存中,占据着内存空间,列表存放的是元素本身,而生成器存放的是算法,通过next()调用算法实时生成元素,因此生成器所占的内存空间很小。
将列表推导式的方括号[ ]改为小括号( )即可创建一个生成器,即:
list = [i*i for i in range(1,11) if i%2==0] #列表表达式 print(list) #打印列表表达式生成的新列表 list = (i*i for i in range(1,11) if i%2==0) #生成器表达式 print(list) #打印生成器 print(list.__next__()) #跟下面next()用法一样 print(next(list)) #生成元素
执行的结果为:
[4, 16, 36, 64, 100]
<generator object <genexpr> at 0x0000000000432CF0>
4
16
可以看到,列表list一旦被创建,内存中就存放所有元素,而生成器list的元素内容将随着next()函数的调用实时生成,直到最后没有元素可生成,抛出StopIteration错误。
3.生成器函数
生成器函数跟常规定义函数类型,只不过使用yield关键字返回结果而不是return关键字。即:
def test(): yield 1 #相当于return yield 2 g = test() print(g) print(g.__next__()) print(g.__next__())
执行结果如下:
<generator object test at 0x0000000002432CF0> 1 2
生成器函数相比于普通函数的区别:
- 生成器代码更简洁
- 生成器内存占用极少
- 运行方式不同
生成器函数总结:
- 语法上和函数类似:生成器函数和常规函数几乎是一样的。它们都是使用def语句进行定义,差别在于,生成器使用yield语句返回一个值,而常规函数使用return语句返回一个值。
- 自动实现迭代器协议:对于生成器,Python会自动实现迭代器协议,以便应用到迭代背景中(for循环、sum函数)。由于生成器自动实现了迭代器协议,所以,我们可以调用它的next方法,并且,在没有值可以返回的时候,生成器自动产生Stopiteration异常。
- 状态挂起:生成器使用yield语句返回一个值。yield语句挂起该生成器函数的状态,保留足够的信息,以便之后从它离开的地方继续执行。
生成器注意事项:生成器只能遍历一次。
二、迭代器
能够用于for循环的对象均被称为可迭代对象。
(字符串、列表、元组、字典、集合、文件对象)这些都不是可迭代对象,只不过在for循环模式,调用他们内部的__iter__()方法,把他们变成了可迭代对象。即:
x='hello' iter_test = x.__iter__() print(iter_test) print(iter_test.__next__()) print(iter_test.__next__()) print(iter_test.__next__())
执行结果如下:
<str_iterator object at 0x0000000002191358>
h
e
l
在所有可以用于for循环的对象中,生成器还可以被next()函数不断调用并生成下一个值,直到抛出StopIteration错误表示无法继续为止。
像生成器这种可以被next()函数调用并不断生成下一个值的对象被称为迭代器。