罗列 Python 标准库中的生成器函数 (1)

实际编码中,我们可能会碰到这样的需求,实现一个生成器函数,但是实现之前要知道标准库中有什么可用, 否则很可能会重新发明轮子,举个栗子~
实现一个无穷等差数列,首项 start = 0, 公差 step = 2, 很显然你不能用列表的形式实现,不然肯定会内存溢出,你可以直接写一个生成器,但是,为什么不用内置的呢

import itertools

gen = itertools.count(start, step)  # 此时 gen 是一个生成器
for _ in range(100):  # 比如我们想打印前 100 个的值
     print(next(gen))

Python 3 中的 itertools 模块提供了多个生成器函数, 结合使用能实现很多用法。
上面所使用的 itertools.count 函数返回的生成器能生成多个数。 如果不传
入参数, itertools.count 函数会生成从零开始的整数数列。 不过,
我们可以提供可选的 start 和 step 值

说到多个生成器结合使用,我们对上面的例子加个条件,生成的等差数列的最大值不超过 100,很显然 itertools.count 无法做到,此时我们可以用到 itertools 下面的另一个生成器函数 itertools.takewhile()

import itertools

gen = itertools.takewhile(lambda n: n < 100, itertools.count(0, 2))  
for value in gen:  
     print(value)

itertools.takewhile 函数会生成一个使用另一个生成器的生成器, 在指定的条件计算结果为 False 时停止

事实上 Python 标准库提供了很多生成器, 有用于逐行迭代纯文本文件的对象, 还有出色的 os.walk 函数。这个函数在遍历目录树的过程中产出文件名, 因此递归搜索文件系统像for 循环那样简单。另外有些在 itertools 和 functools 模块中,下面按类别列举吧

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

下面在控制台演示各个函数的用法

>>> def vowel(c):
... return c.lower() in 'aeiou'
...
>>> list(filter(vowel, 'Aardvark'))
['A', 'a', 'a']
>>> import itertools
>>> list(itertools.filterfalse(vowel, 'Aardvark'))
['r', 'd', 'v', 'r', 'k']
>>> list(itertools.dropwhile(vowel, 'Aardvark'))
['r', 'd', 'v', 'a', 'r', 'k']
>>> list(itertools.takewhile(vowel, 'Aardvark'))
['A', 'a']
>>> list(itertools.compress('Aardvark', (1,0,1,1,0,1)))
['A', 'r', 'd', 'a']
>>> list(itertools.islice('Aardvark', 4))
['A', 'a', 'r', 'd']
>>> list(itertools.islice('Aardvark', 4, 7))
['v', 'a', 'r']
>>> list(itertools.islice('Aardvark', 1, 7, 2))
['a', 'd', 'a']
2、用于映射的生成器函数
模块 函数 说明
itertools accumulate(it, [func]) 产出累计的总和;如果提供了 func,那么把前两个元素传给它,然后把计算结果和下一个元素传给它,以此类推,最后产出结果
(内置) enumerate(iterable, start=0) 产出由两个元素组成的元祖,结构是 (index, item),其中index 从 start 开始计数,item 则从 iterable 中获取
(内置) map(func, it1, [it2, ..., itN]) 把 it 中的各个元素传给 func,产出结果;如果传入 N 个可迭代的对象,那么 func 必须能接受 N 个参数,而且要并行处理各个可迭代的对象
itertools starmap(func, it) 把 it 中的各个元素传给 func,产出结果;输入的可迭代对象应该产出可迭代的元素 iit,然后以 func(*iit) 这种形式调用 func

下面先单独演示 accumulate(it, [func]) 函数的用法吧,这个用法比较灵活

>>> sample = [5, 4, 2, 8, 7, 6, 3, 0, 9, 1]
>>> import itertools
>>> 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]
>>> list(itertools.accumulate(sample, max)) # 计算最大值
[5, 5, 5, 8, 8, 8, 8, 8, 9, 9]
>>> import operator
>>> list(itertools.accumulate(sample, operator.mul)) # 计算乘积
[5, 20, 40, 320, 2240, 13440, 40320, 0, 0, 0]
>>> list(itertools.accumulate(range(1, 10), operator.mul)) # 从1! 到 10!, 计算各个数的阶乘
[1, 2, 6, 24, 120, 720, 5040, 40320, 362880]

接下来演示其他的映射生成器函数

>>> list(enumerate('albatroz', 1)) # 从 1 开始, 为单词中的字母编号
[(1, 'a'), (2, 'l'), (3, 'b'), (4, 'a'), (5, 't'), (6, 'r'), (7, 'o'), (8, 'z')]
>>> list(map(operator.mul, range(11), range(11))) # 从 0 到 10, 计算各个整数的平方 
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
>>> 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 函数
[(0, 2), (1, 4), (2, 8)]
>>> list(itertools.starmap(operator.mul, enumerate('albatroz', 1))) #从 1 开始,根据字母所在的位置, 把字母重复相应的次数 
['a', 'll', 'bbb', 'aaaa', 'ttttt', 'rrrrrr', 'ooooooo', 'zzzzzzzz']
>>> list(itertools.starmap(lambda a, b: b / a, enumerate(itertools.accumulate(sample), 1))) # 计算平均值
[5.0, 4.5, 3.6666666666666665, 4.75, 5.2, 5.333333333333333, 5.0, 4.375, 4.888888888888889, 4.5]
未完待续~
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,142评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,298评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,068评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,081评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,099评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,071评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,990评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,832评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,274评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,488评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,649评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,378评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,979评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,625评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,643评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,545评论 2 352

推荐阅读更多精彩内容