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