python学习笔记六——可迭代的对象、迭代器和生成器

6.可迭代的对象、迭代器和生成器

迭代是数据处理的基石。扫描内存中方不下的数据集时,我们要找一种惰性获取数据项的方式,即按需一次获取一个数据项。这就是迭代器模式。

6.1可迭代对象

6.1.1序列可以迭代的原因

解释器需要迭代对象x时,会自动调用iter(x),内置的iter函数有以下作用:

  • 检查对象是否实现了__iter__方法,如果实现了就调用它,获取一个迭代器。

  • 如果没有实现__iter__方法,但是实现了__getitem__方法,python会创建一个迭代器,尝试按顺序(从索引0开始)获取元素

  • 如果尝试失败,python抛出TypeError异常,通常会提示”C object is not iterable“,其中C是目标迭代对象

6.2 迭代器

6.2.1迭代器的接口

标准的迭代器接口有两个方法:

  • __next__:返回下一个可用的元素,如果没有元素了,抛出StopIteration

  • __iter__:返回self,以便在应该使用可迭代对象的地方使用迭代器,例如在for循环中

6.2.2 一个经典的迭代器

#可迭代对象和迭代器一定不能在一个对象中同时实现,一下为典型的迭代器
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 __iter__(self):
        return SentenceIterator(self.words)
    def __repr__(self):
        return 'Sentence(%s)' % reprlib.repr(self.text)
    
#实现迭代器
class SentenceIterator(self,words):
    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

6.2.3为什么不能把迭代对象同时变成迭代器(添加__next__()方法)

《设计模式:可复用面向对象软件的基础》一书认为:

迭代器模式可以用来:

  • 访问一个聚合对象的内容而无需暴露它的内部表示

  • 支持对聚合对象的多种遍历

  • 为遍历不同的聚合结构提供统一的接口(即支持多态迭代)

为了”支持多种遍历“,必须能从同一个可迭代的实例中获取多个独立的迭代器,而且各个迭代器要能维护自身的内部状态,因此这一模式正确的实现方式是,每次调用iter(my_iterable)都新建一个独立的迭代器,这就是为什么可迭代对象一定不能是自身的迭代器。也就是说,可迭代的对象必须实现 __iter__方法,但不能实现__next__方法

6.2.4 用生成器函数代替迭代器

只要python函数的定义体中有yield关键字,该函数就是生成器函数。调用生成器函数时,会返回一个生成器对象,也就是说,生成器函数就是生成器工厂。

#使用生成器yield代替SentenceIterator类
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 __iter__(self):
        for word in self.words:
            yield word
        return 
    def __repr__(self):
        return 'Sentence(%s)' % reprlib.repr(self.text)

6.2.5 使用生成器表达式改进生成器函数,并且惰性实现

#使用生成器表达式简化生成器函数,并且对__iter__函数惰性实现
import re
import reprlib
​
RE_WORD = re.compile('\w+')
​
class Sentence:
    
    def __init__(self,text):
        self.text = text
    def __iter__(self):
        return (match.group() for match in RE_WORD.finditer(self.text))
    def __repr__(self):
        return 'Sentence(%s)' % reprlib.repr(self.text)

6.3 标准库中的生成器函数

6.3.1 过滤功能

从输入的可迭代对象中产出元素的子集,而且不修改元素本身

模块函数说明
itertoolscompress(it, selector_it)并行处理两个可迭代的对象;如果selector_it中的元素是真值,产出it中对应的元素
itertoolsdropwhile(predicate,it)处理it,跳过predictate的计算结果为真值的元素,然后产出剩下的各个元素(从第一个False值之后不再进一步检查)
(内置)filter(predicate,it)把it中的各个元素传给predicate,如果predicate(item)返回真值,那么产出对应的元素,如果predicate是None,那么只产出对应的元素
itertoolsfilterfalse(predicate,it)与filter函数的作用类似,不过predicate的逻辑是相反的;predicate返回假值时产出对应的元素
itertoolsislice(it, stop)或isclice(it,start,stop,step=1)产出it的切片,作用类似于s[:stop]或s[start:stop:step],不过it可以是任何可迭代的对象,而且这个函数实现的是惰性操作
itertoolstakewhile(predicate, it)predicate返回真值时产出对应的元素,然后立即停止,不再继续检查

6.3.2用于映射的生成器函数

模块函数说明
itertoolsaccumulate(it, [func])产出累计的总和;如果提供了func,那么把前两个元素传给它,然后把计算结果和下一个元素传给它,一次类推,最后产出结果
(内置)enumerate(iterable,start =0)产出由两个元素组成的元祖,结构是(index, item),其中index从startt开始计数,item则从iterable中获取
(内置)map(func,it1,[it2,...,itN])把it中的各个元素传给func,产出结果;如果传入N个可迭代的对象,那么func必须能接受N个参数,而且要并行处理各个可迭代对象
itertoolsstarmap(func, it)把it中的各个元素传给func,产出结果;输入的可迭代对象应该产出可迭代的元素iit,然后func(*iit)这种形式调用func

6.3.3合并多个可迭代对象的生成器函数

模块函数说明
itertoolschain(it1,...,itN)先产出it1中的所有元素,然后产出it2中的所有元素,一次类推,无缝连接在一起
itertoolschain.from_iterable(it)产出it生成的各个可迭代对象的元素,一个接一个,无缝连接在一起;it应该产出可迭代的元素,例如可迭代的对象列表
itertoolsproduct(it1,...,itN,repeat=1)计算笛卡尔积:从输入的各个可迭代对象中获取元素,合并成由N个元素组成的元祖,与嵌套的for循环效果一样;repeat指明重复处理多少次输入的可迭代对象
(内置)zip(it1,...,itN)并行从输入的各个可迭代对象中获取元素,产出由N个元素组成的元祖,只要有一个可迭代的对象到头了,就默默地停止
itertoolszip_longest(it1,...,itN,fillvalue=None)并行从输入的各个可迭代对象中获取元素,产出由N个元素组成的元祖,等到最长的可迭代对象到头后才停止,空缺的值使用fillvalue填充

6.3.4把输入的各个元素扩展成多个输出元素的生成器函数

模块函数说明
itertoolscombinations(it, out_len)把it产出的out_len个元素组合在一起,然后产出
itertoolscombinations_with_replacement(it, out_len)把it产出的out_len个元素组合在一起,然后产出,包含相同的元素组合
itertoolscount(start = 0, step =1)从start开始不断产出数字,按step指定的步幅增加
itertoolscycle(it)从it中产出各个元素,存储各个元素的副本,然后按顺序重复不断的产出各个元素
itertoolspermutations(it, out_len=None)把out_len个it产出的元素排列在一起,然后产出这些排列;out_len的默认值等于len(list(it))
itertoolsrepeat(item, [items])重复不断产出指定的元素,除非提供times,指定次数

6.3.5 用于重新排列元素的生成器函数

模块函数说明
itertoolsgroupby(it, key=None)产出由两个元素组成的元素,形式为(key, group),其中key是分组标准,group是生成器,用于产出分组中的元素
(内置)reversed(seq)从后向前,倒序产出seq中的元素,seq必须是序列,或者是实现了__reversed__特殊方法的对象
itertoolstee(it, n=2)产出一个由n个生成器组成的元祖,每个生成器用于单独产出输入的可迭代对象中的元素

6.3.6可迭代的规约函数

模块函数说明
(内置)all(it)it中的所有元素都为真值时返回True,否则返回False,all([])返回True
(内置)any(it)只要it中的元素为真值就返回True,否则返回False,any([])返回false
(内置)max(it, [key=,][default=])返回it中最大的元素,*key是排序函数,与sorted函数中的一样,如果可迭代的对象为空,返回default
(内置)min(it, [key=,][default=])返回it中最小的元素,*key是排序函数,与sorted函数中的一样,如果可迭代的对象为空,返回default
functoolsreduce(func,it,[initial])把前两个元素传给func,然后把计算结果和第三个元素传给func,以此类推,返回最后的结果,如果提供了initial,把它当作第一个元素传入
(内置)sum(it,start=0)it中的所有元素的总和,如果提供可选的start,会把它加上(计算浮点数的加法时,可以使用math.fsum函数提高精度)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值