第四章迭代器和生成器

二次信任 提交于 2019-12-05 06:46:01

Python CookBook 笔记

第四章迭代器和生成器

4.1 手动遍历迭代器

iter()函数可以将list转换为迭代器,从而使用next()函数获取迭代器结果

4.2实现迭代器协议

Python 的迭代协议要求一个 iter() 方法返回一个特殊的迭代器对象,这个迭代器对象实现了 next() 方法并通过 StopIteration 异常标识迭代的完成

class Node2:

    def __init__(self, value):
        self._value = value
        self._children = []

    def __repr__(self):
        return 'Node({!r})'.format(self._value)

    def add_child(self, node):
        self._children.append(node)

    def __iter__(self):
        return iter(self._children)

    def depth_first(self):
        return DepthFirstIterator(self)


class DepthFirstIterator(object):

    '''
    Depth-first traversal
    '''

    def __init__(self, start_node):
        self._node = start_node
        self._children_iter = None
        self._child_iter = None

    def __iter__(self):
        return self

    def __next__(self):
        # Return myself if just started; create an iterator for children
        if self._children_iter is None:
            self._children_iter = iter(self._node)
            return self._node
        # If processing a child, return its next item
        elif self._child_iter:
            try:
                nextchild = next(self._child_iter)
                return nextchild
            except StopIteration:
                self._child_iter = None
                return next(self)
        # Advance to the next child and start its iteration
        else:
            self._child_iter = next(self._children_iter).depth_first()
            return next(self)

4.3迭代器切片

函数itertools.islice()可以对迭代器和生成器做切片操作

a = (x for x in range(5))
from itertools import islice
for i in islice(a, 1, 3):
    print(i)
# islice() 会消耗掉传入的迭代器中的数据。必须考虑到迭代器是不可逆的这个事实

4.4跳过可迭代对象的开始部分

函数itertools.dropwhile()可根据规则跳过迭代器的某一部分

from itertools import dropwhile
with open('/etc/passwd') as f:
    for line in dropwhile(lambda line: line.startswith('#'), f):
    print(line, end='')

如果知道需要跳过某一段的话也可以使用itertools.islice()

4.5排列组合迭代

itertools的permutations, combinations, combinations_with_replacement模块分别处理可迭代序列的每个位置元素不重复排列,不区分排列书序的组合,同元素可以出现在相同位置的排列

4.6序列的索引迭代

内置的enumerate()函数可以在迭代过程中输出位置索引

4.7同时迭代多个序列

内置的zip()函数可以同时迭代多个序列,迭代结果以len最短的为准

如果想把所有序列迭代完成那么需要使用itertools.zip_longest()函数,不符合迭代长度的元素输出结果为None

zip()函数还可以对序列进行打包生成可迭代序列,dict作用下会生成字典,list作用下会生成元组对组成的列表

headers = ['name', 'shares', 'price']
values = ['ACME', 100, 490.1]
a = zip(headers, values)
print(list(a))
a = zip(headers, values)
print(dict(a))
"""
[('name', 'ACME'), ('shares', 100), ('price', 490.1)]
{'name': 'ACME', 'shares': 100, 'price': 490.1}
"""
# 同样zip迭代序列使用过一次后就被销毁

4.8合并可迭代序列

itertools.chain()可以合并多个序列生成一个迭代器,不会生成一个全新的序列,这种方法要比两个序列相加高效的多,同时不用考虑两个迭代序列类型是否一致

headers = ['name', 'shares', 'price']
values = ('ACME', 100, 490.1)
import itertools
for x in itertools.chain(headers, values):
    print(x)

4.9展开可迭代序列

item = ['Dave', 'Paula', ['Thomas', 'Lewis']]

from collections.abc import Iterable


def flatten(items, ignore_types=(str, bytes)):
    for x in items:
        if isinstance(x, Iterable) and not isinstance(x, ignore_types):
            yield from flatten(x)
        else:
            yield x

for x in flatten(item):
    print(x)

4.10 顺序合并排序后的多个可迭代对象

heapq.merge()可以解决这个问题

a = [1, 2, 3]
b = [6, 8, 9]

import heapq

for i in heapq.merge(a, b):
    print(i)

# heapq.merge()输入的必须是已经排序好的序列

heapq.merge 可迭代特性意味着它不会立马读取所有序列。这就意味着你可以在
非常长的序列中使用它,而不会有太大的开销。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!