Last Updated on
Python中,迭代器和生产器的概念和使用很多,但是也很容易混淆,搞不清楚,下面我们就来详细理解一下迭代器和生成器。
Iterables
要了解迭代器,需要先了解一个概念,Iterables
:可迭代的!
当我们创建列表时,可以一一获取它的内容项。逐一读取其项,例如:
mylist = [1, 2, 3]
for i in mylist:
print(i)
# 输出结果:
1
2
3
那么mylist
就是一个可迭代的对象。在Python中有很多都是可迭代对象,像list
,string
,tuple
,dict
...等等
那么可迭代对象就是迭代器吗? 并不是!
可以说能使用“ for... in...
”的所有对象都是可迭代的对象,为什么呢,因为可迭代对象是定义了可返回迭代器的__iter__
方法的对象。而"for...in...
"就是将可迭代对象通过__iter__
方法生成迭代器然后对迭代器不断的间隙next()
操作,再处理掉最后一次对迭代器next()
时抛出的异常。
看下面示例:
from collections import Iterable
from collections import Iterator
a = [1,2,3]
print(isinstance(a, Iterable))
print(isinstance(a, Iterator))
print(next(a))
b = iter(a)
print(isinstance(b, Iterable))
print(isinstance(b, Iterator))
print(next(b))
print(next(b))
print(next(b))
print(next(b))
# 输出结果:
True
False
抛出 TypeError: 'list' object is not an iterator 错误
True
True
1
2
3
抛出 StopIteration 错误
如上所示,可以看出,列表a是一个可迭代对象,但不是一个迭代器,可以用内置方法iter()
来生成一个迭代器。你会发现迭代器也是一个可迭代的对象。迭代器可以使用next()
方法来输出下一个元素。而非迭代器,不能使用next()
方法。
Iterator
Iterator:迭代器。迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退
迭代器有两个基本的方法:__iter__()
和 __next__()
。
迭代器不会一次性把所有元素加载到内存,而是需要的时候才生成返回结果。
因为实现了__iter__
方法,所以迭代器也是一个可迭代对象。
看下面示例:
from collections import Iterable
from collections import Iterator
a = [1,2,3]
b = iter(a)
print(isinstance(b, Iterable))
print(isinstance(b, Iterator))
print(next(b))
print(next(b))
print(next(b))
print(next(b))
# 输出结果:
True
True
1
2
3
抛出 StopIteration 错误
迭代器每次调用next()方法的时候做两件事:
- 为下一次调用next()方法修改状态
- 生成当前调用的返回结果
这些可迭代的方法很方便,因为您可以随意读取它们,但是您在迭代这些可迭代对象时,虽然迭代器不会一次性把所有元素加载到内存,但是可迭代的对象,如常见的list,dict等,当可迭代对象拥有很多值时,先定义可迭代对象,再进行迭代这就种处理方式就不是我们想要的,会占用大量内存空间。
为了解决这种烦劳,于是有了生成器。
Generators
生成器是迭代器的一种迭代,是一种特殊的迭代器,它具有以下几个特点:
- 只能迭代一次。
- 生成器不会将所有值存储在内存中,它们会即时生成值。
- 生成器可以传入数据。
看下面示例:
from collections import Iterator, Iterable
# 生成器可以使用如下的生成器表达式创建
mygenerator = (x*x for x in range(3))
print(next(mygenerator))
for i in mygenerator:
print(i)
print(isinstance(mygenerator, Iterable))
print(isinstance(mygenerator, Iterator))
# 输出结果:
0
1
4
True
True
生成器是特殊的迭代器,所以也算是迭代器的一种,生成器也是可迭代的。生成器也可以使用next()方法来获取下一个值,但是生成器只能迭代一次。无法重复迭代这是需要注意的。
生成器函数
yield
是与关键字return
一样使用的,不同之处在于该函数将返回生成器。那么这个函数就是生成器函数。也就是说有关键字yield的函数就是生成器函数。
def createGenerator():
mylist = range(3)
for i in mylist:
yield i*i
mygenerator = createGenerator()
print(mygenerator)
for i in mygenerator:
print(i)
# 输出结果:
<generator object createGenerator at 0x1061f4f10>
0
1
4
要掌握yield
,您必须了解在调用函数时,在函数主体中编写的代码不会运行。该函数仅返回生成器对象!
仔细看下面这段说明:
当你第一次使用for调用你的生成器时,它将从头开始运行函数中的代码,直到命中yield
,然后返回第一个yield
的值。然后当你再此迭代时将从上一个yield中断处继续运行,并直到遇到下一个yield
,返回yield
的值,而不是从头运行! 一直这样,知道没有yield值可返回为止。 且由于生成器只能迭代一次,所以如果生成器是空的,则可能是由于生成器函数存在问题,导致程序遇不到yield的值,或者是因为迭代已经结束。
看示例:
def createGenerator(name):
yield 1
yield 2
yield 3
if name == 'amos':
yield 666
mygenerator = createGenerator('amos')
print(mygenerator)
for i in mygenerator:
print(i)
# 输出结果:
<generator object createGenerator at 0x10732df10>
1
2
3
666
这样也可以是一个生成器。理解了yield在生成器函数中的作用就可以更好的编写自己的生成器函数。
有任何问题,欢迎留言讨论