0%

python-cookbook-ch4

终于考完了,开始更新啦!

Chapter 4

Iterators and Generators
这一章的内容个人其实很少用到,但是又感觉还是比较重要,所以可能记录的点比较多,甚至于全部记录

  1. 手动消费一个迭代器(iterator)
    使用next(iterator[, default])函数
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    with open('/etc/passwd') as f:
    try:
    while True:
    line = next(f)
    print(line, end='')
    except StopIteration:
    pass
    ## 或者
    with open('/etc/passwd') as f:
    while True:
    line = next(f, None)
    if line is None:
    break
    print(line, end='')
    也即,当传入第二个参数的时候,将会返回第二个参数作为默认值,而不是抛出StopIteration异常
  1. 通过在自定义类中实现__iter__方法来使其可以作为迭代器被使用(类似于Java中的Iterator接口需要实现hasNext以及next函数一样)。需要注意的是,__iter__返回的需要是一个实现了__next__方法的对象

  2. 通过在函数中使用yield来实现一个自定义的迭代模式(跳过)

  3. __reversed__方法使得可以通过reversed(iterator)的方式来直接倒序遍历某一个迭代器,如果没有实现__reversed__方法就只能手动将迭代器转化为list再倒序遍历,而这将有可能耗费大量的内容

  4. 迭代器的切片
    使用itertools.islice(iterator, startIndex, stopIndex)来得到迭代器的切片。需要注意的是,该函数会使用迭代器,而迭代器是无法逆转的,如果介意这一点的话,可以考虑先转成list

  5. 根据条件消耗掉迭代器的前n个元素

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

    用于去除文件中开头的所有注释

    注意dropwhile遇到不满足的条件的即会跳出而(line for line in f if not line.startswith('#'))则会去除所有的注释,而不只是开头的。

  6. 排列组合
    使用itertools.permutationsitertools.conbinationitertools.conbination_with_replacement
    分别为全排列,全组合,以及可以重复的全组合
    第一个参数均为可遍历对象,第二个可选参数为选择的元素的个数

    1
    2
    3
    4
    from itertools import conbination_with_replacement
    items = ['a', 'b', 'c']
    print(conbination_with_replacement(items, 2))
    # [('a', 'a'), ('a', 'b'), ('a', 'c'), ('b', 'c'), ('b', 'b'), ('c', 'c')]
  7. 使用zip来同时遍历两个等长数组

    1
    2
    3
    4
    a = list(range(10))
    b = list(reversed(range(10)))
    for x, y in zip(a, b):
    print(x, y)
  8. 拼接遍历两个容器
    使用itertools.chain,使用方法非常简单

    1
    2
    3
    4
    5
    from itertools import chain
    a = [1,2,3.4]
    b = set(['a', 'b', 'c'])
    for x in chain(a, b):
    print(x)

    注意:
    chain的特殊之处在于

    1. 比起a + b来说效率更高,由于两个list相加会创建一个新的list,但是chain并不是(此处假设a, blist)
    2. 可以对不同类型进行拼接,如上述所示的,一个是tuple,而另一个是list
      同时,chain并不会对容器的特性进行整合,如在两个set上进行chain操作时,并不会对两个set中相同元素进行去重
  9. flattening一个嵌套的序列

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from collections 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(items):
    print(x)

    其中:

    • ignore_types用于过滤一些可迭代对象,如str以及bytes
    • yield from用于在一个生成器函数中调用另一个生成器函数
  10. 合并两个已排序序列(归并)

    1
    2
    3
    4
    5
    6
    import heapq
    a = [1,4,7,10]
    b = [2,5,6,11]
    for x in heapq.merge(a, b):
    print(x)
    # 1,2,4,5,6,7,10,11

    注意:

    • merge并不会检查两个序列是否已经排好序
    • merge也不会生成一个中间对象,而是返回一个迭代器,所以效率很高