在python中,我们可以使用下面的for-in循环迭代一个列表
numbers = [1, 2, 3]
for n in numbers:
print(n)
但是for-in循环的原理是怎样的呢?这里就涉及到了迭代器相关的部分
迭代器协议
Python的迭代器协议要求实现__iter__方法,__iter__方法会返回一个迭代器对象,这个迭代器对象实现了__next__方法,并且通过抛出StopIteration异常标识迭代的完成。
根据迭代器协议,一个可能的迭代器实现是这样的:
class InfiniteProducer(object):
def __next__(self):
return "hello world"
class MyIterator(object):
def __iter__(self):
return InfiniteProducer()
for i in MyIterator():
print(i)
在这里,我们用两个类实现了迭代器协议,在MyIterator类中,我们在__iter__中返回了一个InfiniteProducer迭代器对象,在这个迭代器对象中,我们实现了__next__方法,这个__next__方法会一直产出同样的值。
在这里,我们使用InfiniteProducer这个类来实现__next__方法,然后用它从迭代器中获取值。
实际上,在迭代器协议中,__next__在哪里定义并不重要,重要的是__iter__要返回带有__next__方法的对象。
所以从实用的角度出发,我们可以将__next__方法和__iter__方法实现在同一个类里面,像下面这样:
class MyIterator(object):
def __iter__(self):
return self
def __next__(self):
return "hello world"
for i in MyIterator():
print(i)
现在,因为MyIterator实现了__iter__方法,所以它是可迭代的,同时因为它还实现了__next__方法,所以它又是一个迭代器。
因为这个类实现了__next__方法,所以在__iter__方法中返回实例自身,就满足了迭代器协议。
停止迭代器
上面的迭代器会一直返回值,如何停止迭代器呢?
根据迭代器协议,我们需要抛出StopIteration异常来终止一个迭代器
比如,如果我们要在迭代10次以后终止,我们可以这么写
class LimitProducer(object):
def __init__(self):
self.iter_nums = 0
self.iter_total_count = 10
def __next__(self):
if self.iter_nums < self.iter_total_count:
self.iter_nums += 1
return "hello world"
raise StopIteration
class MyIterator(object):
def __iter__(self):
return LimitProducer()
for i in MyIterator():
print(i)
生成器
python的生成器提供了一种实现迭代器协议的简单方法
我们上面一直产出值的迭代器,可以通过生成器这样实现:
def iterator():
while True:
yield "hello world"
同样地,通过抛出StopIteration异常可以终止一个迭代器
def iterator():
iter_total_count = 10
iter_nums = 0
while True:
if iter_nums < iter_total_count:
iter_nums += 1
yield "hello world"
else:
raise StopIteration
串联迭代器
生成器可以串联起来,构建像管道一样的数据处理算法,数据处理时,每次只处理一个元素
test_l = range(10)
def square(seq):
for i in seq:
yield i**2
def incr(seq):
for i in seq:
yield i + 1
test_res = incr(square(test_l))
for i in test_res:
print(i)
现在我们来解答开头的问题:for-in 循环是怎么迭代列表的?
对一个列表进行迭代,实际上会先调用列表的__iter__方法获得迭代器,然后在这个迭代器上面调用__next__方法从中获取值
l_iterator = iter([1, 2, 3]) # 获取迭代器
print([i for i in dir(l_iterator) if i in ("__iter__", "__next__")])
>>> ['__iter__', '__next__']
print(l_iterator.__next__()) # 从迭代器获取一个值
>>> 1
总结
为了支持迭代,对象需要实现迭代器协议
可以通过类、生成器、生成器表达式实现一个迭代器
生成器是实现迭代器协议的一个简单方法