# Iterator & Iterable
Iterable: 实现了 __iter__
方法的对象
Iterator: 实现了 __iter__
和 __next__
方法的对象
Python 中关于迭代有两个概念,第一个是 Iterable,第二个是 Iterator,协议规定 Iterable 的 __iter__
方法会返回一个 Iterator, Iterator 的 __next__
方法(Python 2 里是 next)会返回下一个迭代对象,如果迭代结束则抛出 StopIteration 异常。同时,Iterator 自己也是一种 Iterable,所以也需要实现 Iterable 的接口,也就是 __iter__
,这样在 for 当中两者都可以使用。Iterator 的 __iter__
只需要返回自己就行了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 a = [1 , 2 , 3 ] print(isinstance (a, Iterable)) print(isinstance (a, Iterator)) iterator_a = iter (a) print(isinstance (iterator_a, Iterator)) for i in a: print(i, end=' ' ) print() for i in iterator_a: print(i, end=' ' )
# for 循环后备机制
for 为了兼容性有两种机制,如果对象有 __iter__
会使用迭代器,但是如果对象没有 __iter__
,但是实现了 __getitem__
,会改用下标迭代的方式。
1 2 3 4 5 6 7 8 9 10 11 12 class Company : def __init__ (self, employees ): self.employees = employees def __getitem__ (self, index ): return self.employees[index] companies = Company(['A' , 'B' , 'C' ]) for c in companies: print(c)
# 为什么存在 Iterable 和 Iterator
Python 中许多方法直接返回 Iterator,如果 Iterator 自己不是 Iterable 的话,就很不方便,需要先返回一个 Iterable 对象,再让 Iterable 返回 Iterator。
生成器表达式也是一个 Iterator,显然对于生成器表达式直接使用 for 是非常重要的。那么为什么不只保留 Iterator 的接口而还需要设计 Iterable 呢?
许多对象比如 list、dict,是可以重复遍历的,甚至可以同时并发地进行遍历,通过 __iter__
每次返回一个独立的迭代器,就可以保证不同的迭代过程不会互相影响。
而生成器表达式之类的结果往往是一次性的,不可以重复遍历,所以直接返回一个 Iterator 就好。让 Iterator 也实现 Iterable 的兼容就可以很灵活地选择返回哪一种。
总结来说 Iterator 实现的 __iter__
是为了兼容 Iterable 的接口,从而让 Iterator 成为 Iterable 的一种实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 a = [1 , 2 , 3 ] b = [4 , 5 , 6 ] c = zip (a, b) print(c, type (c)) print(isinstance (c, Iterator)) for i in c: print(i) for i in c: print(i) print('*' * 10 ) c_list = list (zip (a, b)) for i in c_list: print(i) for i in c_list: print(i)
# 自定义迭代器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 from collections.abc import Iterator, Iterableclass Company : def __init__ (self, employees ): self.employees = employees def __iter__ (self ): return MyIterator(self.employees) class MyIterator (Iterator ): def __init__ (self, iter_list ): self.iter_list = iter_list self.index = 0 def __next__ (self ): try : iter_item = self.iter_list[self.index] except IndexError: raise StopIteration self.index += 1 return iter_item company = Company(['A' , 'B' , 'C' ]) for c in company: print(c) company_iter = iter (company) while True : try : print(next (company_iter)) except StopIteration: break