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 过滤功能

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

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

6.3.2用于映射的生成器函数

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

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

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

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

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

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

模块 函数 说明
itertools groupby(it, key=None) 产出由两个元素组成的元素,形式为(key, group),其中key是分组标准,group是生成器,用于产出分组中的元素
(内置) reversed(seq) 从后向前,倒序产出seq中的元素,seq必须是序列,或者是实现了__reversed__特殊方法的对象
itertools tee(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
functools reduce(func,it,[initial]) 把前两个元素传给func,然后把计算结果和第三个元素传给func,以此类推,返回最后的结果,如果提供了initial,把它当作第一个元素传入
(内置) sum(it,start=0) it中的所有元素的总和,如果提供可选的start,会把它加上(计算浮点数的加法时,可以使用math.fsum函数提高精度)

猜你喜欢

转载自blog.csdn.net/jasonzhoujx/article/details/81506284
今日推荐