概述 Python
使用yield
关键字来构造生成器,并以迭代器的方式工作。每个生成器都是一个迭代器,生成器实现迭代器接口。
本文主要内容
迭代器的内部实现方式
Python
中实现传统迭代器模式
生成器的实现方式
传统迭代器如何被生成器替代
利用标准库里的通用生成器
使用yield
合并生成器
生成器和协程很像,但实际上差距很大
单词序列 通过实现一个Sentence
类来解释迭代
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 RE_WORD = re.compile ('\w+' ) class Sentence : def __init__ (self, text ): self.text = text self.words = RE_WORD.findall(text) def __getitem__ (self, index ): return self.words[index] def __len__ (self ): return len (self.words) def __repr__ (self ): return 'Sentence(%s)' % reprlib.repr (self.text)
为什么Sentence是可迭代的 当解释器需要迭代一个对象时,其会调用内置方法__iter__
,调用顺序
检查对象是否实现了__iter__
,如果实现了,获取迭代器
如果没有实现__iter__
,但是实现了__getitem__
,Python
会创建一个迭代器,然后会按顺序获取值
如果都没有,那么会抛出异常
这就是Sentence
能迭代的原因,其实现了__getitem__
。事实上,标准库序列都实心了__iter__
。对于__getietm__
的支持有可能会被去掉。Python3.4
检查是否可迭代的最准确的方式是iter(x)
可迭代和迭代器
可迭代,对象内置iter
能够获取一个迭代器。Python
从可迭代对象中获取迭代器。
迭代器的标准接口有两个方法
__next__
: 返回下一个值,如果没有更多值了,抛出StopIteration
异常
__iter__
: 返回迭代器自身
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 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
传统迭代器 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 RE_WORD = re.compile ('\w+' ) class Sentence : def __init__ (self, text ): self.text = text self.words = RE_WORD.findall(text) def __repr__ (self ): return 'Sentence(%s)' % reprlib.repr (self.text) def __iter__ (self ): return SentenceIterator(self.words) class SentenceIterator : def __init__ (self, words ): self.words = words self.index = 0 def __next__ (self ): try : word = self.words[self.index] except IndexError: raise StopIteration() self.index += 1 return word def __iter__ (self ): return self
生成器方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 RE_WORD = re.compile ('\w+' ) class Sentence : def __init__ (self, text ): self.text = text self.words = RE_WORD.findall(text) def __repr__ (self ): return 'Sentence(%s)' % reprlib.repr (self.text) def __iter__ (self ): for word in self.words: yield word return
生成器如何工作 当调用yield
时,返回一个生成器对象,换句话说,生成器方法是个生成器工厂
1 2 3 4 5 6 def gen_123 (): yield 1 yield 2 yield 3
更偷懒的实现方式 1 2 3 4 5 6 7 8 9 10 11 12 13 RE_WORD = re.compile ('\w+' ) class Sentence : def __init__ (self, text ): self.text = text def __repr__ (self ): return 'Sentence(%s)' % reprlib.repr (self.text) def __iter__ (self ): for match in RE_WORD.finditer(self.text): yield match.group()
生成器表达式
RE_WORD = re.compile('\w+')
class Sentence:
def __init__(self, text):
self.text = text
def __repr__(self):
return 'Sentence(%s)' % reprlib.repr(self.text)
def __iter__(self):
return (match.group() for match in RE_WORD.finditer(self.text))
迭代器和协程 Python2.5
加入了协程
生成器产生数据 协程消耗数据