在 Python 中,迭代特性远比我们想象中运用的多,很多我们平常忽略的东西都用到对象能迭代的特性,比如
- for
- collection type construction and extension
- looping over text file line by line
- list, dict, set comprehension
- unpacking
- many built-in function
Iterable 与 Iterator
Iterable 返回一个 Iterator (通过定义 __iter__
方法)
Iterator 要求定义 __iter__
和 __next__
其中前者往往返回 self,后者逐个返回元素直到没有元素时抛出 StopIteration
检测一个对象是不是 Iterator 最好的方法是 isinstance(obj, abc.Iterator)
, 即是你的 obj 不是继承自 abc.Iterator
,但只要你的对象实现了 __iter__
和 __next__
方法就会返回 True
还有要注意的一点是最好把 Iterable 和 Iterator 分开,原因是 Iterable 往往要求能多次迭代,而 Iterator 迭代完后就没有了
一个最为普通的 Iterator
import re
RE_WORD = re.compile('\w+')
class Sentence:
def __init__(self, text):
self.words = RE_WORD.findall(text)
def __iter__(self):
return SentenceIterator(self.words)
class SentenceIterator:
def __init__(self, words):
self.words = words
self.index = index
def __next__():
try:
word = self.words[self.index]
except IndexError:
raise StopIteration
self.index += 1
return word
def __iter__():
return self
显然这样定义很繁琐,所以 Python 中有很多语法糖来帮助你 :)
Generator Function
Generator Function 是含有 yield 的函数,调用 Generator Gunction 返回一个 Generator 对象,而 Generator 对象内部实现了 Iterator 协议,因此支持迭代
class Sentence:
def __init__(self, text):
self.words = RE_WORD.findall(text)
def __iter__(self):
for word in self.words:
yield word
还可以让我们上面 Sentence 的实现更加 Lazy,节约内存
class Sentence:
def __init__(self, text):
self.text = text
def __iter__(self):
for match in RE_WORD.finditer(self.text):
yield match.group()
Python 中类似 list comprehension, 还有 generator comprehension, 作为 generator function 的语法糖,generator comprehension 直接返回一个 generator 对象
class Sentence:
def __init__(self, text):
self.text = text
def __iter__(self):
return (match.group() for match in RE_WORD.finditer(self.text))
推荐阅读: Generator Tricks for Systems Programmers
网友评论