迭代器
Iterable
定義
class Iterable(metaclass=ABCMeta): __slots__ = () @abstractmethod def __iter__(self): while False: yield None @classmethod def __subclasshook__(cls, C): if cls is Iterable: if any("__iter__" in B.__dict__ for B in C.__mro__): return True return NotImplemented
由定義可知Iterable必然包含__iter__函數
Iterator
定義
class Iterator(Iterable): __slots__ = () @abstractmethod def __next__(self): 'Return the next item from the iterator. When exhausted, raise StopIteration' raise StopIteration def __iter__(self): return self @classmethod def __subclasshook__(cls, C): if cls is Iterator: if (any("__next__" in B.__dict__ for B in C.__mro__) and any("__iter__" in B.__dict__ for B in C.__mro__)): return True return NotImplemented
從定義可知Iterator包含__next__和__iter__函數,當next超出範圍時將拋出StopIteration事件
類型關係
#! /usr/bin/python#-*-coding:utf-8-*-from collections import Iterator,Iterable# 迭代器s = 'abc'l = [1,2,3]d=iter(l)print(isinstance(s,Iterable)) # Trueprint(isinstance(l,Iterable)) # Trueprint(isinstance(s,Iterator)) # Falseprint(isinstance(l,Iterator)) # Falseprint(isinstance(d,Iterable)) # Trueprint(isinstance(d,Iterator)) # True
理論上你可以使用next()來執行__next__(),直到迭代器拋出StopIteration 實際上系統提供了for .. in ..的方式來解析迭代器
l = [1,2,3,4]for i in l: print(i) # 執行結果 # 1# 2# 3# 4
產生器 generator
產生器的本質是一個迭代器
#! /usr/bin/python#-*-coding:utf-8-*-from collections import Iterator,Iterables = (x*2 for x in range(5))print(s)print('Is Iterable:' + str(isinstance(s,Iterable)))print('Is Iterator:' + str(isinstance(s,Iterator)))for x in s: print(x)# 執行結果 # <generator object <genexpr> at 0x000001E61C11F048># Is Iterable:True# Is Iterator:True# 0# 2# 4# 6# 8
函數中如果存在yield 則該函數是一個產生器對象 在每一次執行next函數時該函數會在上一個yield處開始執行,並在下一個yield處返回(相當於return)
def foo(): print("First") yield 1 print("Second") yield 2f = foo()print(f)a = next(f)print(a)b = next(f)print(b)# <generator object foo at 0x0000020B697F50F8># First# 1# Second# 2
執行個體
#! /usr/bin/python#-*-coding:utf-8-*-def add(s,x): return s+xdef gen(): for i in range(4): yield ibase = gen()# 由於gen函數中存在yield,所以# for 迴圈本質是建立了兩個generator object,而非執行函數# base = (add(i,10) for i in base)# base = (add(i,10) for i in base)for n in [1,10]: base = (add(i,n) for i in base)# 這裡才開始展開產生器# 第一個產生器展開# base = (add(i,10) for i in base)# base = (add(i,10) for i in range(4))# base = (10,11,12,13)## 第二個產生器展開# base = (add(i,10) for i in (10,11,12,13))# base = (20,21,22,23)print(list(base)) # [20,21,22,23]