itertools常用方法

interator tips:

从Python3.4开始,检查对象x是否迭代,最准确的方法是调用iter(x)函数,如果不可迭代,再处理TypeErro异常。这比isinstance(x, abc.iterable)更准确,因为iter(x)函数会考虑到__getitem__方法,而abc.Iterable类不考虑。

检查对象x是否是迭代器最好的方式是调用isinstance(x, abc.Iterator)

Iterables vs Iterators

如果对象实现了能返回迭代器的__iter__方法,那么对象就是可迭代的。序列都可以迭代,因为实现了__getitem__方法, 而且其参数是从零开始的索引,这种对象也可以迭代。

迭代器是这样的对象,实现了无参数的__next__方法,返回序列中的下一个元素,如果没有元素了,就抛出StopIteration异常,Python中的迭代器还实现了__iter__方法(必须return self),因此迭代器也可以迭代。

可迭代对象和迭代器之间的关系:Python从可迭代的对象中获取迭代器。

generator 生成器

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

所有的生成器都是迭代器,因为生成器完全实现了迭代器接口。

ArithmeticProgression Generator

def aritprog_gen(begin, step, end=None):
    result = type(begin + step)(begin)
    forever = end is None
    index = 0
    while forever or result < end:
        yield result
        index += 1
        result = begin + step * index
    
import itertools
gen = itertools.takewhile(lambda n: n < 3, itertools.count(1, .5))
list(gen)
[1, 1.5, 2.0, 2.5]

Generator Functions n The Standard Library (filter)

def vowel(c):
    return c.lower() in 'aeiou'
list(itertools.filterfalse(vowel, 'Aardvark')) # filter内置函数的反用
['r', 'd', 'v', 'r', 'k']
list(itertools.dropwhile(vowel, 'Aardvark')) # 在条件为false之后的第一次, 返回迭代器中剩下来的项
['r', 'd', 'v', 'a', 'r', 'k']
list(itertools.takewhile(vowel, 'Aardvark')) # 在vowel返回False时停止
['A', 'a']
list(itertools.compress('Aardvark', (1, 0, 1, 1, 0, 1)))  # 并行比较两个可迭代对象,如果后者元素为True, 产出前者的值
['A', 'r', 'd', 'a']
list(itertools.islice('Aardvark', 1, 7, 2))  # 产出前者的切片,主要是惰性操作
['a', 'd', 'a']

Generator Functions (map)

sample = [5,4,2,8,7,6,3,0,9,1]
list(itertools.accumulate(sample))
[5, 9, 11, 19, 26, 32, 35, 35, 44, 45]
list(itertools.accumulate(sample, min))
[5, 4, 2, 2, 2, 2, 2, 0, 0, 0]
import operator
list(itertools.accumulate(sample, operator.mul))
[5, 20, 40, 320, 2240, 13440, 40320, 0, 0, 0]
list(map(operator.mul, range(11), [2, 4, 8]))
[0, 4, 16]
list(map(lambda a, b: (a, b), range(11), [2, 4, 8])) # zip built-in  function does
[(0, 2), (1, 4), (2, 8)]
list(itertools.starmap(operator.mul, enumerate('albatroz', 1))) # [operator.mul(*('a', 1))]
['a', 'll', 'bbb', 'aaaa', 'ttttt', 'rrrrrr', 'ooooooo', 'zzzzzzzz']
list(itertools.starmap(lambda a, b: b/a, enumerate(itertools.accumulate(sample), 1))) # average
[5.0,
 4.5,
 3.6666666666666665,
 4.75,
 5.2,
 5.333333333333333,
 5.0,
 4.375,
 4.888888888888889,
 4.5]

Generator Functions (merging)

list(itertools.chain('ABC', range(2)))
['A', 'B', 'C', 0, 1]
list(itertools.chain(enumerate('ABC')))  # 传入一个参数,没什么卵用
[(0, 'A'), (1, 'B'), (2, 'C')]
list(itertools.chain.from_iterable(enumerate('ABC')))
[0, 'A', 1, 'B', 2, 'C']
list(zip('ABC', range(5), [10, 20, 30, 40]))
[('A', 0, 10), ('B', 1, 20), ('C', 2, 30)]
list(itertools.zip_longest('ABC', range(5), fillvalue='?'))
[('A', 0), ('B', 1), ('C', 2), ('?', 3), ('?', 4)]

Generator FUnctions (Cartesian)笛卡尔积

list(itertools.product('ABC', range(2)))
[('A', 0), ('A', 1), ('B', 0), ('B', 1), ('C', 0), ('C', 1)]
suits = 'spades hearts diamonds clubs'.split()
list(itertools.product('AK', suits))
[('A', 'spades'),
 ('A', 'hearts'),
 ('A', 'diamonds'),
 ('A', 'clubs'),
 ('K', 'spades'),
 ('K', 'hearts'),
 ('K', 'diamonds'),
 ('K', 'clubs')]
list(itertools.product('ABC'))
[('A',), ('B',), ('C',)]
list(itertools.product('ABC', repeat=2))
[('A', 'A'),
 ('A', 'B'),
 ('A', 'C'),
 ('B', 'A'),
 ('B', 'B'),
 ('B', 'C'),
 ('C', 'A'),
 ('C', 'B'),
 ('C', 'C')]
list(itertools.product('AB', range(2), repeat=2))
[('A', 0, 'A', 0),
 ('A', 0, 'A', 1),
 ('A', 0, 'B', 0),
 ('A', 0, 'B', 1),
 ('A', 1, 'A', 0),
 ('A', 1, 'A', 1),
 ('A', 1, 'B', 0),
 ('A', 1, 'B', 1),
 ('B', 0, 'A', 0),
 ('B', 0, 'A', 1),
 ('B', 0, 'B', 0),
 ('B', 0, 'B', 1),
 ('B', 1, 'A', 0),
 ('B', 1, 'A', 1),
 ('B', 1, 'B', 0),
 ('B', 1, 'B', 1)]

一个元素产出多个值

list(itertools.islice(itertools.count(1, .3), 3))
[1, 1.3, 1.6]
cy = itertools.cycle('ABC')
next(cy)
'A'
list(itertools.islice(cy, 7))
['B', 'C', 'A', 'B', 'C', 'A', 'B']
rp = itertools.repeat(7)
next(rp), next(rp)
(7, 7)
list(itertools.repeat(8, 4))
[8, 8, 8, 8]
list(map(operator.mul, range(11), itertools.repeat(5)))  # 为map函数提供固定参数5
[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]
list(itertools.combinations('ABC', 2))
[('A', 'B'), ('A', 'C'), ('B', 'C')]
list(itertools.combinations_with_replacement('ABC', 2))
[('A', 'A'), ('A', 'B'), ('A', 'C'), ('B', 'B'), ('B', 'C'), ('C', 'C')]
list(itertools.permutations('ABC', 2))
[('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'C'), ('C', 'A'), ('C', 'B')]

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

list(itertools.groupby('LLLLAAGGG'))
[('L', ),
 ('A', ),
 ('G', )]
for char, group in itertools.groupby('LLLLAAGGG'):
    print(char, '->', list(group))
L -> ['L', 'L', 'L', 'L']
A -> ['A', 'A']
G -> ['G', 'G', 'G']
animals = ['duck', 'eagle', 'rat', 'giraffe', 'bear', 'bat', 'dolphin', 'shark', 'lion']
animals.sort(key=len)
animals
['rat', 'bat', 'duck', 'bear', 'lion', 'eagle', 'shark', 'giraffe', 'dolphin']
for length, group in itertools.groupby(animals, len):
    print(length, '->', list(group))
3 -> ['rat', 'bat']
4 -> ['duck', 'bear', 'lion']
5 -> ['eagle', 'shark']
7 -> ['giraffe', 'dolphin']
for length, group in itertools.groupby(reversed(animals), len):
    print(length, '->', list(group))
7 -> ['dolphin', 'giraffe']
5 -> ['shark', 'eagle']
4 -> ['lion', 'bear', 'duck']
3 -> ['bat', 'rat']
list(itertools.tee('ABC'))
[, ]
g1, g2 = itertools.tee('ABC')
next(g1)
'A'
next(g2)
'A'
next(g2)
'B'
list(g1)
['B', 'C']
list(zip(*itertools.tee('ABC')))
[('A', 'A'), ('B', 'B'), ('C', 'C')]

New Syntax in Python3.3: yield from

def chain(*iterables):
    for i in iterables:
        yield from i
list(chain('ABBC', range(3)))
['A', 'B', 'B', 'C', 0, 1, 2]

yiled from 除了可以代替循环, 还会创建通道,把内层生成器直接与外层生成器的客户端联系起来。把生成器当成协程使用时,这个通道特别重要,不仅能为客户端代码生成值,还能使用客户端代码提供的值。

Iterable Reducing Functions (可迭代规约函数)

all([1, 0, 3])
False
all([])
True
any([1, 0, 3])
True
any([])
False
g = (n for n in [0, 0.0, 7, 8])
any(g)
True
next(g)
8

iter 一个鲜为人知的用法

传入两个参数,使用常规的函数或任何可调用的对象创建迭代器。第一个参数必须是可调用对象,用于不断调用产出各个值;第二个值是哨符,这个是标记值,当可调用的对象返回这个值时,出发迭代器抛出StropIteration异常

from random import randint
def d6():
    return randint(1, 6)
d6_iter = iter(d6, 1)  # 但是不会输出1
for roll in d6_iter:
    print(roll)
3
4
2

有个实用的例子,逐行读取文件,直到遇到空行或达文件末尾为止:

with open('mydata.txt') as fp:
    for line in iter(fp.readline, ''):
        process_line(line)

Iterator vs Generator

  • 从接口上来看,迭代器协议定义了两个方法:__next____iter__。生成器对象实现了这两个方法,因此从这方面来看,所有的生成器都是迭代器。
  • 从实现方式来看,生成器可以用yield或是生成器表达式。
  • 从概念上来说,迭代器用于遍历集合,从中产出元素。生成器可能无需遍历集合就能生成值,如range函数
def fibonacci():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a+b

你可能感兴趣的:(itertools常用方法)