流畅的python14 章可迭代的对象、迭代器 和生成器
2021-06-19 14:05
标签:协议 rto 获取 abc 赋值 输出 过滤 isl ror 迭代是数据处理的基石。扫描内存中放不下的数据集时,我们要找到一种惰性获取数据项的方式,即按需一次获取一个数据项。这就是迭代器模式(Iterator pattern)。 迭代器用于从集合中取出元素;而生成器用于“凭空”生成元素。通过斐波纳契数列能很好地说明二者之间的区别:斐波纳契数 ?re.findall 函数返回一个字符串列表,里面的元素是正则表达式的 示例 14-2 测试 Sentence 实例能否迭代 ? 传入一个字符串,创建一个 Sentence 实例。 序列可以迭代的原因:iter函数 解释器需要迭代对象 x 时,会自动调用 iter(x)。内置的 iter 函数有以下作用。 可迭代的对象 ? 使用可迭代的对象构建迭代器 it。 StopIteration 异常表明迭代器到头了。Python 语言内部会处理 for循环和其他迭代上下文(如列表推导、元组拆包,等等)中的StopIteration 异常。 标准的迭代器接口有两个方法。 迭代器 迭代器是这样的对象:实现了无参数的 __next__ 方法,返回序列中的下一个元素;如果没有元素了,那么抛出 StopIteration 异常。Python 中的迭代器还实现了 __iter__ 方法,因此迭代器也可以迭代。 使用迭代器模式实现 Sentence 类 生成器函数的工作原理 目前实现的几版 Sentence 类都不具有惰性,因为 __init__ 方法急迫地构建好了文本中的单词列表,然后将其绑定到 self.words 属性上。 re.finditer 函数是 re.findall 函数的惰性版本,返回的不是列表,而是一个生成器,按需生成 re.MatchObject 实例。如果有很多匹配,re.finditer 函数能节省大量内存。我们要使用这个函数让第 4版 Sentence 类变得懒惰,即只在需要时才生成下一个单词。代码如示 ? 不再需要 words 列表。 生成器表达式可以理解为列表推导的惰性版本:不会迫切地构建列表,而是返回一个生成器,按需惰性生成元素。也就是说,如果列表推导是制造列表的工厂,那么生成器表达式就是制造生成器的工厂。 ? gen_AB 函数与示例 14-6 中的一样。 使用生成器表达式实现 Sentence类 这里不是生成器函数了(没有 yield),而是使用生成器表达式构建生成器,然后将其返回。不过,最终的效果一样:调用 __iter__ 方法会得到一个生成器对象。 compress(it, 并行处理两个可迭代的对象;如果 selector_it dropwhile(predicate, 处理 it ,跳过 predicate 的计算结果为真值的元 把 it 中的各个元素传给 predicate ,如果 filterfalse(predicate, 与 filter 函数的作用类似,不过 predicate 的 islice(it, stop) 或 产出 it 的切片,作用类似于 s[:stop] 或 takewhile(predicate, predicate 返回真值时产出对应的元素,然后立 流畅的python14 章可迭代的对象、迭代器 和生成器 标签:协议 rto 获取 abc 赋值 输出 过滤 isl ror 原文地址:https://www.cnblogs.com/chenxuming/p/9690444.html可迭代的对象、迭代器和生成器
列中的数有无穷个,在一个集合里放不下。不过要知道,在 Python社区中,大多数时候都把迭代器和生成器视作同一概念。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 __getitem__(self, index):
return self.words[index] ?
def __len__(self): ?
return len(self.words)
def __repr__(self):
return ‘Sentence(%s)‘ % reprlib.repr(self.text) ?
全部非重叠匹配。
? self.words 中保存的是 .findall 函数返回的结果,因此直接返回
指定索引位上的单词。
? 为了完善序列协议,我们实现了 __len__ 方法;不过,为了让对象
可以迭代,没必要实现这个方法。
? reprlib.repr 这个实用函数用于生成大型数据结构的简略字符串表
示形式。>>> s = Sentence(‘"The time has come," the Walrus said,‘) # ?
>>> s
Sentence(‘"The time ha... Walrus said,‘) # ?
>>> for word in s: # ?
... print(word)
The
time
has
come
the
Walrus
said
>>> list(s) # ?
[‘The‘, ‘time‘, ‘has‘, ‘come‘, ‘the‘, ‘Walrus‘, ‘said‘]
? 注意,__repr__ 方法的输出中包含 reprlib.repr 方法生成的
...。
? Sentence 实例可以迭代,稍后说明原因。
? 因为可以迭代,所以 Sentence 对象可以用于构建列表和其他可迭代
的类型。
可迭代的对象与迭代器的对比
使用 iter 内置函数可以获取迭代器的对象。如果对象实现了能返回迭代器的 __iter__ 方法,那么对象就是可迭代的。序列都可以迭代;实现了 __getitem__ 方法,而且其参数是从零开始的索引,这种
对象也可以迭代。
我们要明确可迭代的对象和迭代器之间的关系:Python 从可迭代的对象中获取迭代器。
下面是一个简单的 for 循环,迭代一个字符串。这里,字符串 ‘ABC‘是可迭代的对象。背后是有迭代器的,只不过我们看不到:>>> s = ‘ABC‘
>>> for char in s:
... print(char)
...
A
B
C
###如果没有 for 语句,不得不使用 while 循环模拟,要像下面这样写:
>>> s = ‘ABC‘
>>> it = iter(s) # ?
>>> while True:
... try:
... print(next(it)) # ?
... except StopIteration: # ?
... del it # ?
... break # ?
...
A
B
C
? 不断在迭代器上调用 next 函数,获取下一个字符。
? 如果没有字符了,迭代器会抛出 StopIteration 异常。
? 释放对 it 的引用,即废弃迭代器对象。
? 退出循环。
__next__
返回下一个可用的元素,如果没有元素了,抛出 StopIteration异常。
__iter__
返回 self,以便在应该使用可迭代对象的地方使用迭代器,例如在 for 循环中。典型的迭代器
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): #与前一版相比,这里只多了一个 __iter__ 方法。这一版没有
#__getitem__ 方法,为的是明确表明这个类可以迭代,因为实现了
#__iter__ 方法。
return SentenceIterator(self.words) #根据可迭代协议,__iter__ 方法实例化并返回一个迭代器。
class SentenceIterator:
def __init__(self, words):
self.words = words #SentenceIterator 实例引用单词列表。
self.index = 0#self.index 用于确定下一个要获取的单词。
def __next__(self):
try:
word = self.words[self.index] #获取 self.index 索引位上的单词。
except IndexError:
raise StopIteration() #如果 self.index 索引位上没有单词,那么抛出 StopIteration 异
常。
self.index += 1
return word
def __iter__(self): #实现 self.__iter__ 方法。
return self
生成器函数
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
只要 Python 函数的定义体中有 yield 关键字,该函数就是生成器函数。调用生成器函数时,会返回一个生成器对象。也就是说,生成器函数是生成器工厂。惰性实现
这样就得处理整个文本,列表使用的内存量可能与文本本身一样多(或许更多,这取决于文本中有多少非单词字符)。如果只需迭代前几个单词,大多数工作都是白费力气。
只要使用的是 Python 3,思索着做某件事有没有懒惰的方式,答案通常都是肯定的。
例 14-7 所示。示例 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()
? finditer 函数构建一个迭代器,包含 self.text 中匹配 RE_WORD
的单词,产出 MatchObject 实例。
? match.group() 方法从 MatchObject 实例中提取匹配正则表达式的
具体文本。
生成器函数已经极大地简化了代码,但是使用生成器表达式甚至能把代
码变得更简短。生成器表达式
>>> def gen_AB(): # ?
... print(‘start‘)
... yield ‘A‘
... print(‘continue‘)
... yield ‘B‘
... print(‘end.‘)
...
>>> res1 = [x*3 for x in gen_AB()] # ?
start
continue
end.
>>> for i in res1: # ?
... print(‘-->‘, i)
...
--> AAA
--> BBB
>>> res2 = (x*3 for x in gen_AB()) # ?
>>> res2 # ?
? 列表推导迫切地迭代 gen_AB() 函数生成的生成器对象产出的元
素:‘A‘ 和 ‘B‘。注意,下面的输出是 start、continue 和 end.。
? 这个 for 循环迭代列表推导生成的 res1 列表。
? 把生成器表达式返回的值赋值给 res2。只需调用 gen_AB() 函数,
虽然调用时会返回一个生成器,但是这里并不使用。
? res2 是一个生成器对象。
? 只有 for 循环迭代 res2 时,gen_AB 函数的定义体才会真正执
行。for 循环每次迭代时会隐式调用 next(res2),前进到 gen_AB 函
数中的下一个 yield 语句。注意,gen_AB 函数的输出与 for 循环中
print 函数的输出夹杂在一起。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):
return (match.group() for match in RE_WORD.finditer(self.text))
生成器表达式是语法糖:完全可以替换成生成器函数,不过有时使用生成器表达式更便利。标准库中的生成器函数
用于过滤的生成器函数
模块
函数
说明
itertools
selector_it)
中的元素是真值,产出 it 中对应的元素
itertools
it)
素,然后产出剩下的各个元素(不再进一步检
查)
内置
filter(predicate, it)
predicate(item) 返回真值,那么产出对应的元
素;如果 predicate 是 None ,那么只产出真值元
素
itertools
it)
逻辑是相反的: predicate 返回假值时产出对应
的元素
itertools
islice(it, start,
stop, step=1)
s[start:stop:step] ,不过 it 可以是任何可迭代
的对象,而且这个函数实现的是惰性操作
itertools
it)
即停止,不再继续检查
上一篇:数组赋值问题
文章标题:流畅的python14 章可迭代的对象、迭代器 和生成器
文章链接:http://soscw.com/index.php/essay/95983.html