第十四章 - 可迭代的对象、迭代器和生成器
可迭代的对象、迭代器和生成器
1、生成器实现了迭代器的接口,所以生成器也是迭代器
2、迭代器从集合中取出元素,生成器用于“凭空”生成元素
3、yield from 合并生成器,创建通道
4、Python中所有集合都可以迭代
14.1 Sentence类第一版:单词序列
示例14-1
import re import reprlib RE_WORD = re.compile("\w+") class Sentence(object): def __init__(self, text): self.text = text self.words = RE_WORD.findall(text) def __getitem__(self, item): # 实现了getitem方法,Python也会自动创建一个迭代器。任何Python序列都实现了__getitem__方法;标准的序列也都实现了__iter__方法。 return self.words[item] def __len__(self): return len(self.words) def __repr__(self): return "Sentence(%s)" % reprlib.repr(self.text) s = Sentence("The time has come, the Walrus said") print(s) for word in s: print(word) print(list(s)) >>> Sentence('The time has...e Walrus said') The time has come the Walrus said ['The', 'time', 'has', 'come', 'the', 'Walrus', 'said']
序列可以迭代的原因:iter函数
解释器需要迭代对象x时,会自动调用iter(x)。
内置的iter函数有以下作用:
1、检查对象是否实现了__iter__方法,如果实现了就调用他/她,获取一个迭代器。
2、如果没有实现__iter__方法,但是实现了__getitem__方法,python会创建一个迭代器,尝试按顺序获取元素。
3、如果尝试失败,Python抛出TypeError异常(“C object is not iterable”)。
从Python3.4开始,检查对象X能否迭代,最准确的方式是:调用iter(x)函数,如果不可迭代,再处理TypeError异常。
14.2 可迭代对象与迭代器的对比
可迭代对象:
使用iter内置函数可以获取迭代器的对象,如果对象实现了能返回迭代器的__iter__方法,那么对象就是可迭代对象。
注: Python语言内部会处理for循环和其他迭代上下文中的StopIteration异常(while不会)。
迭代器:
只需要实现__next__和__iter__两个方法,它就是迭代器。
14.10 Python3.3中新出现的语法:yield from
如果生成器函数需要产出另一个生成器生成的值,传统的解决方法是使用嵌套的for循环。
示例1
def chain(*iterable): for it in iterable: for i in it: yield i s = "ABC" ss = tuple(range(10)) aa = list(chain(s, ss)) print(aa) >>>> ['A', 'B', 'C', 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
示例2
def chain2(*iterable): for it in iterable: yield from it # yield from i完全代替了内层的for循环 s = "ABC" ss = tuple(range(10)) aa = list(chain2(s, ss)) print(aa) >>>> ['A', 'B', 'C', 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
示例3
""" iter(source, sentinel=None) # sentinel哨符,当可调用对象返回这个值时触发迭代器抛出StopIteration异常 """ def file_read(file): with open(file) as fp: for line in iter(fp.readline, "\n"): process_line(line)
示例4
yield关键字只能把最近的外层函数变成生成器函数,下面的示例将获取到一个死循环的函数,而不是生成器
def f(): def do_yield(n): yield n x = 0 while True: x += 1 do_yield(x) print(f) >>>> <function f at 0x014A2300>
示例5
基于yield from来实现
def b(): def do_yield(n): yield n x = 0 while True: x += 1 yield from do_yield(x) print(b()) >>>> <generator object b at 0x009F66F0>