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', <itertools._grouper at 0x108ad79e8>),
 ('A', <itertools._grouper at 0x108ad7550>),
 ('G', <itertools._grouper at 0x108ad7978>)]
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'))
[<itertools._tee at 0x108ad22c8>, <itertools._tee at 0x108ae4cc8>]
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
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,490评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,581评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,830评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,957评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,974评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,754评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,464评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,847评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,995评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,137评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,819评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,482评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,023评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,149评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,409评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,086评论 2 355

推荐阅读更多精彩内容