Python 可迭代对象与迭代器
Kong Liangqian Lv6

定义一个可迭代对象

Python中的Iterable译为可迭代对象,在一个类中,只要定义了一个__iter__,那么他就是一个可迭代对象

1
2
3
4
5
6
7
from collections.abc import Iterable, Iterator  

class A():
def __iter__(self):
print("entered iter")
return None
print(isinstance(A(), Iterable)) # True

一个可迭代对象可以通过for 循环触发迭代,for循环一个对象,就是运行他的__iter__,在上述文件后添加如下内容,

1
2
3
a = A()
for i in a:
print(i)

运行结果为

1
2
3
4
5
entered iter
Traceback (most recent call last):
File "test.py", line 13, in <module>
for i in a:
TypeError: iter() returned non-iterator of type 'NoneType'

注意,entered iter已经被打印了

但是报错了,报错的内容为iter函数(iter() 调用的就是__iter__)返回的内容不是一个迭代器,也就是说,for循环的操作是,通过__iter__ 函数返回一个迭代器,然后开始逐个输出迭代器中的内容

我们尝试返回一个迭代器,我们知道,一个list是可以被for循环输出的,因此,一个list的__iter__返回的内容必然是一个可以迭代出list中内容的迭代器

1
2
3
4
5
6
7
8
9
from collections.abc import Iterable, Iterator  

class A():
def __iter__(self):
print("entered iter")
return [1,2,3].__iter__()
a = A()
for i in a:
print(i)

输出结果

1
2
3
1
2
3

定义一个迭代器

在一个类中,只要定义了一个__iter__,那么他就是一个可迭代对象,是一个可以通过for 关键字来触发__iter__函数运行的可迭代对象。

虽然他是一个可以被for触发的一个可迭代对象,但是目前还不知道迭代的内容是什么,所以我们需要定义迭代的内容,这就是迭代器

上面我们知道__iter__返回的内容需要是一个迭代器,只要一个类中定义__next__方法,他就是一个迭代器,因此我们需要在__iter__中返回自己即可

1
2
3
4
5
6
7
8
9
10
11
12
13
from collections.abc import Iterable, Iterator  

class A():
def __iter__(self):
print("entered iter")
return self

def __next__(self):
return 1

a = A()
for i in a:
print(i)

输出是内容是,无穷无尽的1

1
2
3
4
5
6
1
1
1
1
1
...

这说明,for的确是先调用__iter__,然后再调用__next__

想要让循环停止,需要给一个判定条件,抛出StopIteration异常,即可

生成器

通过上面迭代器的定义可知,写一个迭代器还是比较复杂的,需要定义两个魔法函数,有一种特殊的迭代器,他叫生成器,他的写法就十分的简单

在函数中,把return 改为yield 即可

1
2
3
4
5
6
7
8
9
10
11
def fibonacci(n): # 生成器函数 - 斐波那契
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
f = fibonacci(10) # f 是一个迭代器,由生成器返回生成
print(f.__next__()) # 或者使用next(f),返回0

fibonacci(10)不会直接运行,每调用一次next,函数就执行到yield把值返回。

 Comments