Python编程:可迭代的对象、迭代器和迭代器

1.Sentence类第1版:单词序列

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

        我们从下面的例子中开始对迭代器进行叙述。

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)

        上段代码中,re.findall返回一个字符串列表,里面的元素都是正则表达式的全部非重叠匹配。将其返回的结果保存在self.words中。最后,reprlib.repr这个实用函数用于生成大型数据结构的简略字符串表示形式。

1.1序列可以迭代的原因:iter函数

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

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

(2)如果没有实现iter方法,但是实现了getitem方法,Python会创建一个迭代器,尝试按顺序获取元素。

(3)如果尝试失败,会抛出TypeError。

2.可迭代的对象与迭代器的对比

        可迭代对象:使用iter内置函数可以获取迭代器的对象。如果对象实现了能返回会迭代器的iter方法,那么对象就是可迭代的。序列都可以迭代,实现了getitem方法,而且其参数是从零开始的索引,这种对象就是可迭代的。

        迭代器:实现了无参数的_next_方法,返回序列中的下一个元素,如果没有元素了,那么就抛出StopIteration异常。Python中的迭代器还实现了_iter_方法,因此迭代器是可以迭代的。

        并且,我们要明确可迭代的对象和迭代器之间的关系,Python从可迭代的对象中获取迭代器。标准的迭代器接口包含两个方法。

(1)_next_:返回下一个可用的元素,如果没有元素了,就抛出StopIteration异常。

(2)_iter_:返回self,以便在应该使用可迭代对象的地方使用迭代器,例如在for循环中。

2.1把Sentence变成迭代器:坏主意

        构建可迭代的对象和迭代器时经常会出现错误,原因是混淆了二者。要知道,可迭代的对象有个_iter_方法,每次都实例化了一个新的迭代器。而迭代器要实现next方法,返回单个元素,此外,还要实现_iter_方法,返回实例本身。

        因此,迭代器可以迭代,但是可迭代的对象不是迭代器。

3.Sentence第2版:生成器函数

        先使用生成器函数编写的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):
        for word in self.words:
            yield word
        return 

        该段代码,在iter方法中,迭代self.words,并产出当前的word。要注意,return语句并不是必要的,这个函数可以直接落空,自动返回。

        在Python中函数定义体中有yield的关键字,该函数就是生成器函数。调用生成器函数,就会返回一个生成器对象。也就是说,生成器函数就是生成器工厂。生成器函数会创建一个生成器对象,包装生成器函数的定义体。把生成器传给next()函数时,生成器函数会向前,执行函数定义体的下一个yield语句,返回产出值,并在函数定义体的当前位置暂停。最终,函数的定义体返回时,外层的生成器对象会抛出StopIteration异常。

4.标准库中的生成器函数

        标准库中提供了很多生成器,下面介绍一下常用的生成器函数。

4.1用于过滤的生成器函数

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

模块函数说明
itertoolscompress(it,selector_it)并行处理讲个可迭代的对象,如果selector_it中的元素是真值,产出it中对应的元素。
itertoolsdropwhile(predicate,it)处理it,跳过predicate的计算结果为真值的元素,然后产出剩下的各个元素。
内置filter(predicate,it)把it中的各个元素传给predicate,如果返回真值,就产出对应的元素,如果为None,那么只产出真值元素。
itertoolsfilterfalse(predicate,it)把it中的各个元素传给predicate,如果返回假值,就产出对应的元素。与filter相反。
itertoolsislice(it,stop)产出it的切片,作用类似于s[:stop],并且这个函数实现的是惰性操作。
itertoolstakewhile(predicate,it)predicate返回真值时产出对应的元素,然后立即停止,不再继续检查。

4.2用于映射的生成器函数

        在输入的单个可迭代对象中的各个元素上做计算,然后返回结果。如果输入来自多个可迭代的对象,第一个可迭代对象到头后就停止输出。

模块函数说明
itertoolsaccumulate(it,[func])产出累积的总和;如果提供了func,那么把前两个元素传给它,然后把计算结果和下一个元素传给它,以此类推,产出最后结果。
内置enumerate(iterable,start=0)

产出的两个元素组成的元组,结构是(index, item)

,其中index从start开始计数,item从iterable获取。

内置map(func,it1,[it2,…,itN])把it中的各个元素传给func,产出结果,如果传入N个可迭代的对象,那么func必须可以接受N个参数,而且要并行处理各个可迭代的的对象。
itertoolsstarmap(func,it)

把it中的各个元素传给func,产出结果,输入的可迭代对象应该产出可迭代的元素iit,然后以func(*iit)

这种形式调用func。

4.3用于合并的生成器函数

        这些函数都从输入的可迭代对象中产出元素。chain和chain.form_iterable按顺序(一个接一个)处理输入的可迭代对象,而product、zip和zip_longest并行处理输入的各个可迭代对象。

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

4.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=Noine)把out_len个it产出的元素排列在一起,然后产出这些排列,out_len的默认值等于len(list(it))。
itertools

repeat(item,[times])

重复不断地产出指定元素,除非提供times,指定次数。

4.5用于重新排列的生成器函数

        有些函数生成器用于产出输入的可迭代对象中的全部元素,不过会以某种方式重新排列。其中,有两个函数会返回多个生成器,分别是itertools.groupby和itertools.tee。这一组里的另一个函数生成器。内置的reversed函数,是本节所述函数中唯一一个不接受可迭代的对象,而只接受序列为参数的函数。

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

4.6可迭代的归约函数

        下面表格中的函数都接受一个可迭代的对象,然后返回单个结果,这些函数叫做归约函数。

模块函数说明
内置all(it)

it中都为真值时返回Ture,否则返回False。all([])返回Ture。

内置any(it)只要it中有元素为真值就返回Ture,否则返回False。all([])返回False。
内置max(it, [key=,] [default=])返回it中值最大的元素:key为排序函数,与sorted函数一样,如果可迭代对象为空,返回default。
内置min(it, [key=,] [default=])返回it中值最小的元素:key为排序函数,与sorted函数一样,如果可迭代对象为空,返回default。
functoolsreduce(func, it, [inital])把前两个元素传给func,然后把计算的结果和第三个元素传给func,以此类推,返回最后的结果。如果提供了initial,把它当做第一个元素传入。
内置sum(it, start=0)it中所有元素的总和,如果提供了start会把它加上。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值