- # 第 14 章 可迭代的对象, 迭代器和生成器
- # 迭代是数据处理的基石. 扫描内存中放不下的数据集时, 我们要找到一种惰性获取数据项的方式, 即按需一次获取一个数据项. 这就是迭代器模式 (Iterator pattern).
- # 所有生成器都是迭代器, 因为生成器完全实现了迭代器接口.
- # 迭代器用于从集合中取出元素; 而生成器用于 "凭空" 生成元素.
- # 14.1 Sentence 类第 1 版: 单词序列
- # 示例 14-1 sentence.py: 把句子划分为单词序列
- import re
- import reprlib
- 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):# 为了完善序列协议, 我们实现了__len__方法; 不过, 为了让对象可以迭代, 没必要实现这个方法.
- return len(self.words)
- def __repr__(self):# reprlib.repr 这个实用函数用于生成大型数据结构的简略字符串表示形式.
- return 'Sentence(%s)'%reprlib.repr(self.text)
- # 示例 14-2 测试 Sentence 实例能否迭代
- s=Sentence('"The time has come,"the Walrus said,')
- print(s)
- for word in s:
- print(word)
- print(list(s))
- print(s[0],s[5],s[-1])
- # 任何 Python 序列都可迭代的原因是, 它们都实现了 __getitem__ 方法.
- # 从 Python 3.4 开始, 检查对象 x 能否迭代, 最准确的方法是: 调用 iter(x) 函数, 如果不可迭代, 再处理 TypeError 异常.
- # 14.2 可迭代的对象与迭代器的对比
- # 标准的迭代器接口有两个方法.
- # __next__返回下一个可用的元素, 如果没有元素了, 抛出 StopIteration 异常.
- # __iter__返回 self, 以便在应该使用可迭代对象的地方使用迭代器, 例如在 for 循环中.
- # 迭代器迭代器是这样的对象: 实现了无参数的 __next__ 方法, 返回序列中的下一个元素; 如果没有元素了, 那么抛出 StopIteration 异常.
- # 14.3 Sentence 类第 2 版: 典型的迭代器
- # 例 14-4 sentence_iter.py: 使用迭代器模式实现 Sentence 类
- import re
- import reprlib
- 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
- # 迭代器模式可用来:
- # 访问一个聚合对象的内容而无需暴露它的内部
- # 表示支持对聚合对象的多种遍历
- # 为遍历不同的聚合结构提供一个统一的接口 (即支持多态迭代)
- # 14.4 Sentence 类第 3 版: 生成器函数
- import re
- import reprlib
- 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 # 这个 return 语句不是必要的; 这个函数可以直接 "落空", 自动返回.
- # 不管有没有 return 语句, 生成器函数都不会抛出 StopIteration 异常, 而是在生成完全部值之后会直接退出.
- # 生成器函数的工作原理
- # 只要 Python 函数的定义体中有 yield 关键字, 该函数就是生成器函数.
- # 调用生成器函数时, 会返回一个生成器对象. 也就是说, 生成器函数是生成器工厂.
- # 只要 Python 函数中包含关键字 yield, 该函数就是生成器函数.
- # 14.5 Sentence 类第 4 版: 惰性实现
- # 示例 14-7 sentence_gen2.py: 在生成器函数中调用 re.finditer 生成器函数, 实现 Sentence 类
- import re
- import reprlib
- 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()
- # 14.6 Sentence 类第 5 版: 生成器表达式
- # 生成器表达式可以理解为列表推导的惰性版本: 不会迫切地构建列表, 而是返回一个生成器, 按需惰性生成元素.
- # 示例 14-9 sentence_genexp.py: 使用生成器表达式实现 Sentence 类
- import re
- import reprlib
- RE_WORD=re.compile('\w+')
- class Sentence:
- def __init__(self,text):
- self.text=text
- def __repr__(self):
- return 'Sentence(%)'%.reprlib.repr(self.text)
- def __iter__(self):
- return (match.group() for match in RE_WORD.finditer(self.text))
- # 生成器表达式是语法糖: 完全可以替换成生成器函数, 不过有时使用生成器表达式更便利. 下一节说明生成器表达式的用途.
- # 14.7 何时使用生成器表达式
- # 生成器表达式是创建生成器的简洁句法, 这样无需先定义函数再调用.
- # 不过, 生成器函数灵活得多, 可以使用多个语句实现复杂的逻辑, 也可以作为协程使用
- # 14.8 另一个示例: 等差数列生成器
- # 典型的迭代器模式作用很简单 -- 遍历数据结构.
- # 示例 14-11 ArithmeticProgression 类
- class ArithmeticProgression:
- def __init__(self,begin,step,end=None):
- self.begin=begin
- self.step=step
- self.end=end
- def __iter__(self):
- result=type(self.begin+self.step)(self.begin)
- forever=self.end is None
- index=0
- while forever or result <self.end:
- yield result
- index +=1
- result=self.begin+self.step*index
- # 示例 14-10 演示 ArithmeticProgression 类的用法
- ap=ArithmeticProgression(0,1,3)
- print(list(ap))
- ap=ArithmeticProgression(1,.5,3)
- print(list(ap))
- ap=ArithmeticProgression(0,1/3,1)
- print(list(ap))
- from fractions import Fraction
- ap=ArithmeticProgression(0,Fraction(1,3),1)
- print(list(ap))
- from decimal import Decimal
- ap=ArithmeticProgression(0,Decimal('.1'),.3)
- print(list(ap))
- # 使用 itertools 模块生成等差数列
- # Python3.4 中的 itertools 模块提供了 19 个生成器函数, 结合起来使用能实现很多有趣的用法.
- import itertools
- gen=itertools.count(1,.5)
- print(next(gen),next(gen),next(gen))
- # 不过, itertools.takewhile 函数则不同, 它会生成一个使用另一个生成器的生成器,
- # 在指定的条件计算结果为 False 时停止. 因此, 可以把这两个函数结合在一起使用.
- gen=itertools.takewhile(lambda n:n<3,itertools.count(1,.5))
- print(list(gen))
- # 示例 14-13 aritprog_v3.py: 与前面的 aritprog_gen 函数作用相同
- import itertools
- def aritprog_gen(begin,step,end=None):
- first=type(begin+step)(begin)
- ap_gen=itertools.count(first,step)
- if end is not None:
- ap_gen=itertools.takewhile(lambda n:n<end,ap_gen)
- return ap_gen
- # 示例 14-13 想表达的观点是, 实现生成器时要知道标准库中有什么可用, 否则很可能会重新发明轮子.
- # 14.9 标准库中的生成器函数
- # 示例 14-15 演示 itertools.accumulate 生成器函数
- sample=[5,4,2,8,7,6,3,0,9,1]
- import itertools
- print(list(itertools.accumulate(sample)))# 计算总和.
- print(list(itertools.accumulate(sample,min)))# 计算最小值.
- print(list(itertools.accumulate(sample,max)))# 计算最大值.
- import operator
- print(list(itertools.accumulate(sample,operator.mul)))# 计算乘积.
- print(list(itertools.accumulate(range(1,11),operator.mul)))# 从 1! 到 10!, 计算各个数的阶乘.
- # 示例 14-17 演示用于合并的生成器函数
- print(list(itertools.chain('ABC',range(2))))
- print(list(itertools.chain(enumerate('ABC'))))
- print(list(itertools.chain.from_iterable(enumerate('ABC'))))
- print(list(zip('ABC',range(5))))
- print(list(zip('ABC',range(5),[10,20,30,40])))
- print(list(itertools.zip_longest('ABC',range(5))))
- print(list(itertools.zip_longest('ABC',range(5),fillvalue='?')))
- #14.10 Python3.3 中新出现的句法: yield from
- def chain(*iterables):
- for i in iterables:
- yield from i
- print(list(chain('ABC',tuple(range(3)))))
- # 除了代替循环之外, yield from 还会创建通道, 把内层生成器直接与外层生成器的客户端联系起来.
- # 14.11 可迭代的归约函数
- # 表 14-6 中的函数都接受一个可迭代的对象, 然后返回单个结果. 这些函数叫 "归约" 函数,"合拢" 函数或 "累加" 函数.
- # 此外, 对 all 和 any 数来说, 有一项重要的优化措施是 reduce 函数做不到的:
- # 这两个函数会短路 (即一旦确定了结果就立即停止使用迭代器).
- # all(it)it 中的所有元素都为真值时返回 True, 否则返回 False;all([]) 返回 True
- # any(it) 只要 it 中有元素为真值就返回 True, 否则返回 False;any([]) 返回 False
- # 14.12 深入分析 iter 函数
- from random import randint
- def d6():
- return randint(1,6)
- d6_iter=iter(d6,1)
- # 第二个值是哨符, 这是个标记值, 当可调用的对象返回这个值时,
- # 触发迭代器抛出 StopIteration 异常, 而不产出哨符.
- print(d6_iter)
- for roll in d6_iter:
- print(roll)
- # 14.13 案例分析: 在数据库转换工具中使用生成器
- # 14.14 把生成器当成协程
- # 14.15 本章小结
- # 14.16 延伸阅读
- def fibonacci():
- a, b = 0, 1
- while True:
- yield a
- a, b = b, a + b
来源: http://www.bubuko.com/infodetail-2756554.html