1. 可迭代对象Iterable:
如果对象实现了
__iter__
方法或实现了__getitem__
方法,且其参数是从零开始索引的,则称为可迭代对象(Iterable)凡是可作用于for循环的对象都是可迭代对象。
python内置的数据类型,像list
、tuple
、dict
、set
、str
等都是可迭代对象。
可迭代对象不是迭代器!!!python从可迭代对象中获取迭代器。
Iterable.__iter__
方法应该返回一个Iterator 实例。
判断是否可迭代对象的方法:
最准确方法是使用iter
函数,但要注意假如不是可迭代对象,Python 会抛出TypeError
异常。要做好异常处理。
不建议使用isinstance(x, Iterable)
的方法。因为该函数判断时没考虑该类只有__getitem__
的时候,所以当自建类时没有自定义__iter__
方法,即使可迭代,仍会判断为False
。
内置的iter
函数有以下作用: (1) 检查对象是否实现了__iter__
方法,如果实现了就调用它,获取一个迭代器。
(2) 如果没有实现__iter__
方法,但是实现了__getitem__
方法,Python 会创建一个迭代器,尝试按顺序(从索引 0 开始)获取元素。 (3) 如果尝试失败,Python 抛出TypeError
异常,通常会提示XXX object is not iterable
。
- 每次调用
iter(iterable object)
,成功的话都新建一个独立的迭代器。
2. 迭代器Iterator:
表示数据流的对象。在流中,能够被
next()
函数调用并不断返回下一个元素,直到没有元素抛出StopIteration
异常。所以迭代器只能往前不能后退。由于迭代器一定会有
__iter__
方法,所以它自身也是一个可迭代对象。
2.1 标准的迭代器含有两个方法:
__next__
:返回下一个可用的元素,如果没元素则抛出StopIteration
异常。
__iter__
:返回self
,以便在应该使用可迭代对象的地方使用迭代器。
2.2 判断是否迭代器的方法:
from collections.abc import Iterator
isinstance(x, Iterator)
2.3 可迭代对象生成迭代器:
iter(Iterable object)
2.4 迭代器遍历的方法:
#使用for语句进行遍历。
迭代时,for 机制的是获取生成器对象,然后每次迭代时隐式调用 next(...)。
#也可以使用next(iterator[, default])函数,该对象需要为迭代器
it = iter(object) #把可迭代对象创建一个迭代器
next(it)
3. 生成器Generator:
只要python函数体中有
yield
关键字,该函数就是生成器函数。调用生成器函数时,会返回一个生成器对象。也就是说,生成器函数是生成器工厂。
>>> def gen(): #生成器函数
... yield 1
...
>>> gen
<function gen at 0x000002193DCCC160>
>>> gen() #生成器对象
<generator object gen at 0x000002193DD23F90>
把生成器传给next()
函数时,生成器函数会向前,执行函数定义体中的下一个 yield 语句,返回产出值,并在函数定义体的当前位置暂停。最终,函数的定义体返回时,外层的生成器对象会抛出StopIteration
异常。与迭代器协议一致。
所以,生成器是迭代器!
生成器的本质:函数定义体体现算法,不会一次性构建出结果,按需惰性地生成元素,从而节省了大量内存。调用者在函数体外使用next()
函数跳转到生成器函数内继续执行函数,遇到yield
关键字则携带其元素值跳回到调用者函数,直到遇到下一个next()
函数跳回到生成器上次跳出的地方继续执行,如此重复。
3.1 创建生成器的方法:
-
函数体中含有
yield
关键字 -
利用列表生成式。
把列表生成式的
[]
改为()
,即创建了生成器
3.2 生成器的方法:
在PEP342中新增了2,3,4方法。
__next()__
:使生成器前进到下一个yield 语句,然后从生成器中获取数据。send()
:除了拥有和__next()__
方法一样的功能外,还允许将参数传给生成器。即不管传什么参数,该参数都会成为生成器函数定义体中对应的 yield 表达式的值。也就是说,send()
方法允许在客户代码和生成器之间双向交换数据。这改变了生成器的性质,变成了==协程==。- 虽然在协程中会使用 yield 产出值,但只是借用了该关键字的性质,与迭代已完全无关!!!
throw()
:让调用方抛出异常close()
:终止生成器
4. 自定义可迭代对象类型简化的演化例子:
-
典型的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
-
优化迭代器类,用生成器函数代替
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
-
将正则匹配改为惰性
class Sentence: def __init__(self, text): self.text = text def __repr__(self): return 'Sentence(%s)' % reprlib.repr(self.text) def __iter__(self): for word in RE_WORD.finditer(self.text): yield word.group()
-
将生成器函数变成生成器表达式
class Sentence: def __init__(self, text): self.text = text def __repr__(self): return 'Sentence(%s)' % reprlib.repr(self.text) def __iter__(self): return (word.group() for word in RE_WORD.finditer(self.text))
There are 0 comments