>>> from env_helper import info; info()
页面更新时间: 2024-04-05 08:24:56
运行环境:
    Linux发行版本: Debian GNU/Linux 12 (bookworm)
    操作系统内核: Linux-6.1.0-18-amd64-x86_64-with-glibc2.36
    Python版本: 3.11.2

11.4. 使用迭代器相关模块

11.4.1. itertools 模块

itertools 模块包含很多常用的迭代器以及用来组合迭代器的函数。 这个模块实现一系列 iterator ,这些迭代器受到APL,Haskell和SML的启发里的函数大致可以分为几类:

  • 已有的迭代器创建新的迭代器的函数。

  • 接受迭代器元素作为参数的函数。

  • 选取部分迭代器输出的函数。

  • 给迭代器输出分组的函数。

创建新的迭代器

itertools.count(start, step)

itertools.count(start, step) 返回一个等分的无限数据流。 初始值默认为0,间隔默认为1,创建一个迭代器,它从 start 值开始,返回均匀间隔的值。

用法如下:

>>> import itertools
>>> itobj = itertools.count(10)
>>> next(itobj); next(itobj);
>>> next(itobj)
12

itertools.cycle(iterable)

itertools.cycle(iterable) 创建一个迭代器,返回 iterable 中所有元素并保存一个副本。 当取完 iterable 中所有元素,返回副本中的所有元素。无限重复。

>>> it_obj2 = itertools.cycle('ABCD')
>>> next(it_obj2)
'A'
>>> next(it_obj2), next(it_obj2), next(it_obj2), next(it_obj2)
('B', 'C', 'D', 'A')

itertools.repeat(object[, times])

itertools.repeat(object[, times]) 创建一个迭代器,不断重复 object 。除非设定参数 times ,否则将无限重复。 这个 object 可以是任意对象。

10 10 10 –>

>>> it_obj3 = itertools.repeat([4,5,6,7],3)
>>> next(it_obj3)
[4, 5, 6, 7]

根据最短输入序列长度停止的迭代器

>>> it_obj4 = itertools.accumulate([1,2,3,4,5])
>>> next(it_obj4)
1
>>> next(it_obj4),next(it_obj4),next(it_obj4),next(it_obj4)
(3, 6, 10, 15)

accumulate()

p [,func]

p0, p0+p1, p0+p1+p2, …

accumulate([1,2,3,4,5]) –> 1 3 6 10 15

chain()

p, q, …

p0, p1, … plast, q0, q1, …

chain(‘ABC’, ‘DEF’) –> A B C D E F

chain.from_iterable()

iterable

p0, p1, … plast, q0, q1, …

chain.from_iterable([‘ABC’, ‘DEF’]) –> A B C D E F

compress()

data, selectors

(d[0] if s[0]), (d[1] if s[1]), …

compress(‘ABCDEF’, [1,0,1,0,1,1]) –> A C E F

dropwhile()

pred, seq

seq[n], seq[n+1], … 从pred首次真值测试失败开始

dropwhile(lambda x: x<5, [1,4,6,4,1]) –> 6 4 1

filterfalse()

pred, seq

seq中pred(x)为假值的元素,x是seq中的元素。

filterfalse(lambda x: x%2, range(10)) –> 0 2 4 6 8

groupby()

iterable[, key]

根据key(v)值分组的迭代器

islice()

seq, [start,] stop [, step]

seq[start:stop:step]中的元素

islice(‘ABCDEFG’, 2, None) –> C D E F G

starmap()

func, seq

func(seq[0]), func(seq[1]), …

starmap(pow, [(2,5), (3,2), (10,3)]) –> 32 9 1000

takewhile()

pred, seq

seq[0], seq[1], …, 直到pred真值测试失败

takewhile(lambda x: x<5, [1,4,6,4,1]) –> 1 4

tee()

it, n

it1, it2, … itn 将一个迭代器拆分为n个迭代器

zip_longest()

p, q, …

(p[0], q[0]), (p[1], q[1]), …

zip_longest(‘ABCD’, ‘xy’, fillvalue=‘-’) –> Ax By C- D-

accumulate()

p [,func]

p0, p0+p1, p0+p1+p2, …

accumulate([1,2,3,4,5]) –> 1 3 6 10 15

chain()

p, q, …

p0, p1, … plast, q0, q1, …

chain(‘ABC’, ‘DEF’) –> A B C D E F

chain.from_iterable()

iterable

p0, p1, … plast, q0, q1, …

chain.from_iterable([‘ABC’, ‘DEF’]) –> A B C D E F

compress()

data, selectors

(d[0] if s[0]), (d[1] if s[1]), …

compress(‘ABCDEF’, [1,0,1,0,1,1]) –> A C E F

dropwhile()

pred, seq

seq[n], seq[n+1], … 从pred首次真值测试失败开始

dropwhile(lambda x: x<5, [1,4,6,4,1]) –> 6 4 1

filterfalse()

pred, seq

seq中pred(x)为假值的元素,x是seq中的元素。

filterfalse(lambda x: x%2, range(10)) –> 0 2 4 6 8

groupby()

iterable[, key]

根据key(v)值分组的迭代器

islice()

seq, [start,] stop [, step]

seq[start:stop:step]中的元素

islice(‘ABCDEFG’, 2, None) –> C D E F G

starmap()

func, seq

func(seq[0]), func(seq[1]), …

starmap(pow, [(2,5), (3,2), (10,3)]) –> 32 9 1000

takewhile()

pred, seq

seq[0], seq[1], …, 直到pred真值测试失败

takewhile(lambda x: x<5, [1,4,6,4,1]) –> 1 4

tee()

it, n

it1, it2, … itn 将一个迭代器拆分为n个迭代器

zip_longest()

p, q, …

(p[0], q[0]), (p[1], q[1]), …

zip_longest(‘ABCD’, ‘xy’, fillvalue=‘-’) –> Ax By C- D-

选择元素

另外一系列函数根据谓词选取一个迭代器中元素的子集。

itertools.filterfalse(predicate, iter) 和 filter() 相反,返回所有让 predicate 返回 false 的元素:

itertools.filterfalse(is_even, itertools.count())

>>> def is_even(num):
>>>     if num %2 == 0:
>>>         return True
>>>     return False
>>> result = itertools.filterfalse( is_even, the_arr)
>>> list(result)
[1, 3, 5, 7, 9]

组合函数

itertools.combinations(iterable, r) 返回一个迭代器,它能给出输入迭代器中所包含的元素的所有可能的 r 元元组的组合。 itertools.permutations(iterable, r=None),取消了保持顺序的限制,返回所有可能的长度为 r 的排列. itertools.combinations_with_replacement(iterable, r) 函数放松了一个不同的限制:元组中的元素可以重复。从概念讲,为每个元组第一个位置选取一个元素,然后在选择第二个元素前替换掉它。

>>> import itertools
>>> x = itertools.combinations([1, 2, 3, 4, 5], 2)
>>> for y in x:
>>>     print(y)
(1, 2)
(1, 3)
(1, 4)
(1, 5)
(2, 3)
(2, 4)
(2, 5)
(3, 4)
(3, 5)
(4, 5)
>>> z = itertools.permutations([1, 2, 3, 4, 5], 2)
>>> for y in z:
>>>     print(y)
(1, 2)
(1, 3)
(1, 4)
(1, 5)
(2, 1)
(2, 3)
(2, 4)
(2, 5)
(3, 1)
(3, 2)
(3, 4)
(3, 5)
(4, 1)
(4, 2)
(4, 3)
(4, 5)
(5, 1)
(5, 2)
(5, 3)
(5, 4)
>>> tt = itertools.combinations_with_replacement([1, 2, 3, 4, 5], 2)
>>> for x in tt:
>>>     print(x)
(1, 1)
(1, 2)
(1, 3)
(1, 4)
(1, 5)
(2, 2)
(2, 3)
(2, 4)
(2, 5)
(3, 3)
(3, 4)
(3, 5)
(4, 4)
(4, 5)
(5, 5)

11.4.2. functools 模块

functools 模块包含了一些高阶函数。 高阶函数 接受一个或多个函数作为输入,返回新的函数。 这个模块中最有用的工具是 functools.partial() 函数。

对于用函数式风格编写的程序,有时会希望通过给定部分参数,将已有的函数构变形称新的函数。考虑一个 Python 函数 f(a, b, c);你希望创建一个和 f(1, b, c) 等价的新函数 g(b, c);也就是说你给定了 f() 的一个参数的值。这就是所谓的“部分函数应用”。从这一部分感受到更加与数学函数更加相近

partial() 接受参数 (function, arg1, arg2, …, kwarg1=value1, kwarg2=value2)。它会返回一个可调用的对象,所以你能够直接调用这个结果以使用给定参数的 function。

>>> import functools
>>>
>>> def log(message, subsystem):
>>>     print('%s: %s' % (subsystem, message))
>>>
>>> server_log = functools.partial(log, subsystem='server')
>>> server_log('start')
server: start

functools.reduce(func, iter, [initial_value]) 持续地在可迭代对象的所有元素上执行操作, 因此它不能够用在无限的可迭代对象上。 func 必须是一个接受两个元素并返回一个值的函数。

functools.reduce() 接受迭代器返回的前两个元素 A 和 B 并计算 func(A, B) 。然后它会请求第三个元素,C,计算 func(func(A, B), C),然后把这个结果再和第四个元素组合并返回,如此继续下去直到消耗整个可迭代对象。

11.4.3. 对元素使用函数: operator 模块

前面已经提到了 operator 模块。它包含一系列对应于 Python 操作符的函数。在函数式风格的代码中,这些函数通常很有用,可以帮你省下不少时间,避免写一些琐碎的仅仅执行一个简单操作的函数。

  • 数学运算: add(),sub(),mul(),floordiv(),abs(), …

  • 逻辑运算: not_(),truth()。

  • 位运算: and_(),or_(),invert()。

  • 比较: eq(),ne(),lt(),le(),gt(),和 ge()。

  • 确认对象: is_(),is_not()。

operator (标准运算符替代函数) 模块包含一组对应于 Python 操作符的函数。比如 operator.add(a, b) (把两个数加起来),operator.ne(a, b) (和 a != b 相同),以及 operator.attrgetter(‘id’) (返回获取 .id 属性的可调用对象)。

>>> the_arr = range(10)
>>> the_arr2 = range(10)
>>> import operator
>>> the_arr3 = operator.add(2,3)
>>> the_arr3
5