itertoolsFunctions creating iterators for efficient looping创建迭代器以实现高效循环的函数


This module implements a number of iterator building blocks inspired by constructs from APL, Haskell, and SML. Each has been recast in a form suitable for Python.该模块实现了许多迭代器构建块,其灵感来自APL、Haskell和SML的构造。每一个都以适合Python的形式重铸。

The module standardizes a core set of fast, memory efficient tools that are useful by themselves or in combination. 该模块标准化了一组快速、内存高效的核心工具,这些工具本身或组合使用都很有用。Together, they form an “iterator algebra” making it possible to construct specialized tools succinctly and efficiently in pure Python.它们共同构成了一个“迭代器代数”,使得在纯Python中简洁高效地构造专用工具成为可能。

For instance, SML provides a tabulation tool: tabulate(f) which produces a sequence f(0), f(1), .... 例如,SML提供了一个制表工具:tabulate(f),它生成序列f(0), f(1), ...The same effect can be achieved in Python by combining map() and count() to form map(f, count()).在Python中,通过组合map()count()来形成map(f, count()),可以实现相同的效果。

These tools and their built-in counterparts also work well with the high-speed functions in the operator module. 这些工具及其内置对应工具也能很好地与operator模块中的高速功能配合使用。For example, the multiplication operator can be mapped across two vectors to form an efficient dot-product: sum(map(operator.mul, vector1, vector2)).例如,乘法运算符可以跨两个向量映射以形成有效的点积:sum(map(operator.mul, vector1, vector2))

Infinite iterators:无限迭代器:

Iterator迭代器

Arguments参数

Results结果

Example实例

count()

start, [step]

start, start+step, start+2*step, …

count(10) --> 10 11 12 13 14 ...

cycle()

p

p0, p1, … plast, p0, p1, …

cycle('ABCD') --> A B C D A B C D ...

repeat()

elem [,n]

elem, elem, elem, … endlessly or up to n times

repeat(10, 3) --> 10 10 10

Iterators terminating on the shortest input sequence:终止于最短输入序列的迭代器:

Iterator迭代器

Arguments参数

Results结果

Example示例

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], starting when pred failsseq[n]seq[n+1]pred失败时开始

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

filterfalse()

pred, seq

elements of seq where pred(elem) is falseseq的元素,其中pred(elem)false

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

groupby()

iterable[, key]

sub-iterators grouped by value of key(v)key(v)值分组的子迭代器

islice()

seq, [start,] stop [, step]

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

islice('ABCDEFG', 2, None) --> C D E F G

pairwise()

iterable

(p[0], p[1]), (p[1], p[2])

pairwise('ABCDEFG') --> AB BC CD DE EF FG

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], until pred fails

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

tee()

it, n

it1, it2, … itn splits one iterator into n

zip_longest()

p, q, …

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

zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-

Combinatoric iterators:组合迭代器:

Iterator迭代器

Arguments参数

Results结果

product()

p, q, … [repeat=1]

cartesian product, equivalent to a nested for-loop笛卡尔乘积,等价于嵌套for循环

permutations()

p[, r]

r-length tuples, all possible orderings, no repeated elementsr长度元组,所有可能的排序,没有重复元素

combinations()

p, r

r-length tuples, in sorted order, no repeated elementsr长度元组,按排序顺序,无重复元素

combinations_with_replacement()

p, r

r-length tuples, in sorted order, with repeated elementsr长度元组,按排序,具有重复元素

Examples示例

Results结果

product('ABCD', repeat=2)

AA AB AC AD BA BB BC BD CA CB CC CD DA DB DC DD

permutations('ABCD', 2)

AB AC AD BA BC BD CA CB CD DA DB DC

combinations('ABCD', 2)

AB AC AD BC BD CD

combinations_with_replacement('ABCD', 2)

AA AB AC AD BB BC BD CC CD DD

Itertool functionsItertool函数

The following module functions all construct and return iterators. 以下模块函数都构造并返回迭代器。Some provide streams of infinite length, so they should only be accessed by functions or loops that truncate the stream.有些提供无限长的流,因此只能由截断流的函数或循环访问。

itertools.accumulate(iterable[, func, *, initial=None])

Make an iterator that returns accumulated sums, or accumulated results of other binary functions (specified via the optional func argument).生成一个迭代器,返回其他二进制函数的累积和或累积结果(通过可选func参数指定)。

If func is supplied, it should be a function of two arguments. 如果提供了func,则它应该是两个参数的函数。Elements of the input iterable may be any type that can be accepted as arguments to func. 输入iterable的元素可以是可以接受为func参数的任何类型。(For example, with the default operation of addition, elements may be any addable type including Decimal or Fraction.)(例如,在默认的加法操作中,元素可以是任何可加类型,包括DecimalFraction。)

Usually, the number of elements output matches the input iterable. 通常,输出的元素数与输入iterable匹配。However, if the keyword argument initial is provided, the accumulation leads off with the initial value so that the output has one more element than the input iterable.但是,如果提供了关键字参数initial,则累加以初始值开始,这样输出比输入iterable多出一个元素。

Roughly equivalent to:大致相当于:

def accumulate(iterable, func=operator.add, *, initial=None):
'Return running totals'
# accumulate([1,2,3,4,5]) --> 1 3 6 10 15
# accumulate([1,2,3,4,5], initial=100) --> 100 101 103 106 110 115
# accumulate([1,2,3,4,5], operator.mul) --> 1 2 6 24 120
it = iter(iterable)
total = initial
if initial is None:
try:
total = next(it)
except StopIteration:
return
yield total
for element in it:
total = func(total, element)
yield total

There are a number of uses for the func argument. func参数有多种用途。It can be set to min() for a running minimum, max() for a running maximum, or operator.mul() for a running product. 对于正在运行的最小值,可以将其设置为min(),对于正在运行的最大值,可以将其设置为max(),对于正在运行的产品,可以将其设置为operatormul()Amortization tables can be built by accumulating interest and applying payments. 摊销表可以通过累积利息和应用付款来建立。First-order recurrence relations can be modeled by supplying the initial value in the iterable and using only the accumulated total in func argument:通过在iterable中提供初始值并仅使用func参数中的累积总和,可以对一阶递归关系进行建模:

>>> data = [3, 4, 6, 2, 1, 9, 0, 7, 5, 8]
>>> list(accumulate(data, operator.mul)) # running product
[3, 12, 72, 144, 144, 1296, 0, 0, 0, 0]
>>> list(accumulate(data, max)) # running maximum
[3, 4, 6, 6, 6, 9, 9, 9, 9, 9]
# Amortize a 5% loan of 1000 with 4 annual payments of 90
>>> cashflows = [1000, -90, -90, -90, -90]
>>> list(accumulate(cashflows, lambda bal, pmt: bal*1.05 + pmt))
[1000, 960.0, 918.0, 873.9000000000001, 827.5950000000001]

# Chaotic recurrence relation https://en.wikipedia.org/wiki/Logistic_map
>>> logistic_map = lambda x, _: r * x * (1 - x)
>>> r = 3.8
>>> x0 = 0.4
>>> inputs = repeat(x0, 36) # only the initial value is used
>>> [format(x, '.2f') for x in accumulate(inputs, logistic_map)]
['0.40', '0.91', '0.30', '0.81', '0.60', '0.92', '0.29', '0.79', '0.63',
'0.88', '0.39', '0.90', '0.33', '0.84', '0.52', '0.95', '0.18', '0.57',
'0.93', '0.25', '0.71', '0.79', '0.63', '0.88', '0.39', '0.91', '0.32',
'0.83', '0.54', '0.95', '0.20', '0.60', '0.91', '0.30', '0.80', '0.60']

See functools.reduce() for a similar function that returns only the final accumulated value.有关仅返回最终累积值的类似函数,请参阅functools.reduce()

New in version 3.2.版本3.2中新增。

Changed in version 3.3:版本3.3中更改: Added the optional func parameter.添加了可选的func参数。

Changed in version 3.8:版本3.8中更改: Added the optional initial parameter.添加了可选的initial参数。

itertools.chain(*iterables)

Make an iterator that returns elements from the first iterable until it is exhausted, then proceeds to the next iterable, until all of the iterables are exhausted. 制作一个迭代器,从第一个iterable返回元素,直到用尽为止,然后继续到下一个iterable,直到用尽所有iterable。Used for treating consecutive sequences as a single sequence. 用于将连续序列视为单个序列。Roughly equivalent to:大致相当于:

def chain(*iterables):
# chain('ABC', 'DEF') --> A B C D E F
for it in iterables:
for element in it:
yield element
classmethodchain.from_iterable(iterable)

Alternate constructor for chain(). chain()的替代构造函数。Gets chained inputs from a single iterable argument that is evaluated lazily. 从延迟计算的单个iterable参数获取链接输入。Roughly equivalent to:大致相当于:

def from_iterable(iterables):
# chain.from_iterable(['ABC', 'DEF']) --> A B C D E F
for it in iterables:
for element in it:
yield element
itertools.combinations(iterable, r)

Return r length subsequences of elements from the input iterable.从输入iterable返回元素的r长度子序列。

The combination tuples are emitted in lexicographic ordering according to the order of the input iterable. 组合元组根据输入iterable的顺序按字典序发出。So, if the input iterable is sorted, the combination tuples will be produced in sorted order.因此,如果对输入iterable进行排序,则组合元组将按排序顺序生成。

Elements are treated as unique based on their position, not on their value. 元素根据其位置而不是价值被视为唯一。So if the input elements are unique, there will be no repeat values in each combination.因此,如果输入元素是唯一的,则每个组合中不会有重复值。

Roughly equivalent to:大致相当于:

def combinations(iterable, r):
# combinations('ABCD', 2) --> AB AC AD BC BD CD
# combinations(range(4), 3) --> 012 013 023 123
pool = tuple(iterable)
n = len(pool)
if r > n:
return
indices = list(range(r))
yield tuple(pool[i] for i in indices)
while True:
for i in reversed(range(r)):
if indices[i] != i + n - r:
break
else:
return
indices[i] += 1
for j in range(i+1, r):
indices[j] = indices[j-1] + 1
yield tuple(pool[i] for i in indices)

The code for combinations() can be also expressed as a subsequence of permutations() after filtering entries where the elements are not in sorted order (according to their position in the input pool):combinations()的代码也可以表示为在筛选元素不按排序顺序(根据其在输入池中的位置)的条目后permutations()的子序列:

def combinations(iterable, r):
pool = tuple(iterable)
n = len(pool)
for indices in permutations(range(n), r):
if sorted(indices) == list(indices):
yield tuple(pool[i] for i in indices)

The number of items returned is n! / r! / (n-r)! when 0 <= r <= n or zero when r > n.0 <= r <= n时返回的项目数为n! / r! / (n-r)!,而当r > n时返回的项数为0

itertools.combinations_with_replacement(iterable, r)

Return r length subsequences of elements from the input iterable allowing individual elements to be repeated more than once.从输入iterable返回元素的r长度子序列,允许单个元素重复多次。

The combination tuples are emitted in lexicographic ordering according to the order of the input iterable. 组合元组根据输入iterable的顺序按字典序发出。So, if the input iterable is sorted, the combination tuples will be produced in sorted order.因此,如果对输入iterable进行排序,则组合元组将按排序顺序生成。

Elements are treated as unique based on their position, not on their value. 元素根据其位置而不是价值被视为唯一。So if the input elements are unique, the generated combinations will also be unique.因此,如果输入元素是唯一的,则生成的组合也将是唯一的。

Roughly equivalent to:大致相当于:

def combinations_with_replacement(iterable, r):
# combinations_with_replacement('ABC', 2) --> AA AB AC BB BC CC
pool = tuple(iterable)
n = len(pool)
if not n and r:
return
indices = [0] * r
yield tuple(pool[i] for i in indices)
while True:
for i in reversed(range(r)):
if indices[i] != n - 1:
break
else:
return
indices[i:] = [indices[i] + 1] * (r - i)
yield tuple(pool[i] for i in indices)

The code for combinations_with_replacement() can be also expressed as a subsequence of product() after filtering entries where the elements are not in sorted order (according to their position in the input pool):combinations_with_replacement()的代码也可以表示为product()的子序列,在筛选元素不按排序顺序(根据其在输入池中的位置)的条目后:

def combinations_with_replacement(iterable, r):
pool = tuple(iterable)
n = len(pool)
for indices in product(range(n), repeat=r):
if sorted(indices) == list(indices):
yield tuple(pool[i] for i in indices)

The number of items returned is (n+r-1)! / r! / (n-1)! when n > 0.n > 0时返回的项目数为(n+r-1)! / r! / (n-1)!

New in version 3.1.版本3.1中新增。

itertools.compress(data, selectors)

Make an iterator that filters elements from data returning only those that have a corresponding element in selectors that evaluates to True. 制作一个迭代器,从data中筛选元素,只返回那些在计算结果为True的选择器中具有相应元素的元素。Stops when either the data or selectors iterables has been exhausted. dataselectors已用完时停止。Roughly equivalent to:大致相当于:

def compress(data, selectors):
# compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F
return (d for d, s in zip(data, selectors) if s)

New in version 3.1.版本3.1中新增。

itertools.count(start=0, step=1)

Make an iterator that returns evenly spaced values starting with number start. 制作一个迭代器,返回从数字start的等距值。Often used as an argument to map() to generate consecutive data points. 通常用作map()的参数,以生成连续的数据点。Also, used with zip() to add sequence numbers. 此外,与zip()一起用于添加序列号。Roughly equivalent to:大致相当于:

def count(start=0, step=1):
# count(10) --> 10 11 12 13 14 ...
# count(2.5, 0.5) -> 2.5 3.0 3.5 ...
n = start
while True:
yield n
n += step

When counting with floating point numbers, better accuracy can sometimes be achieved by substituting multiplicative code such as: (start + step * i for i in count()).当使用浮点数进行计数时,有时可以通过替换乘法代码来实现更高的精度,例如:(start + step * i for i in count())

Changed in version 3.1:版本3.1中更改: Added step argument and allowed non-integer arguments.添加了step参数和允许的非整数参数。

itertools.cycle(iterable)

Make an iterator returning elements from the iterable and saving a copy of each. 制作一个迭代器,从iterable返回元素,并保存每个元素的副本。When the iterable is exhausted, return elements from the saved copy. 当iterable用完时,从保存的副本返回元素。Repeats indefinitely. 无限期重复。Roughly equivalent to:大致相当于:

def cycle(iterable):
# cycle('ABCD') --> A B C D A B C D A B C D ...
saved = []
for element in iterable:
yield element
saved.append(element)
while saved:
for element in saved:
yield element

Note, this member of the toolkit may require significant auxiliary storage (depending on the length of the iterable).注意,工具箱的这个成员可能需要大量的辅助存储(取决于iterable的长度)。

itertools.dropwhile(predicate, iterable)

Make an iterator that drops elements from the iterable as long as the predicate is true; afterwards, returns every element. 制作一个迭代器,只要谓词为true,就从iterable中删除元素;然后,返回每个元素。Note, the iterator does not produce any output until the predicate first becomes false, so it may have a lengthy start-up time. 注意,迭代器在谓词第一次变为false之前不会产生任何输出,因此它可能需要很长的启动时间。Roughly equivalent to:大致相当于:

def dropwhile(predicate, iterable):
# dropwhile(lambda x: x<5, [1,4,6,4,1]) --> 6 4 1
iterable = iter(iterable)
for x in iterable:
if not predicate(x):
yield x
break
for x in iterable:
yield x
itertools.filterfalse(predicate, iterable)

Make an iterator that filters elements from iterable returning only those for which the predicate is False. 制作一个迭代器,从可迭代对象中筛选元素,只返回谓词为False的元素。If predicate is None, return the items that are false. 如果predicateNone,则返回false项。Roughly equivalent to:大致相当于:

def filterfalse(predicate, iterable):
# filterfalse(lambda x: x%2, range(10)) --> 0 2 4 6 8
if predicate is None:
predicate = bool
for x in iterable:
if not predicate(x):
yield x
itertools.groupby(iterable, key=None)

Make an iterator that returns consecutive keys and groups from the iterable. 制作一个迭代器,从iterable返回连续的键和组。The key is a function computing a key value for each element. key是计算每个元素的键值的函数。If not specified or is None, key defaults to an identity function and returns the element unchanged. 如果未指定或为None,则key默认为标识函数,并返回不变的元素。Generally, the iterable needs to already be sorted on the same key function.通常,iterable需要已经在同一个键函数上排序。

The operation of groupby() is similar to the uniq filter in Unix. groupby()的操作类似于Unix中的uniq筛选器。It generates a break or new group every time the value of the key function changes (which is why it is usually necessary to have sorted the data using the same key function). 每次键函数的值更改时,它都会生成一个中断或新组(这就是为什么通常需要使用相同的键函数对数据进行排序)。That behavior differs from SQL’s GROUP BY which aggregates common elements regardless of their input order.这种行为不同于SQL的组,SQL的组通过该组聚合公共元素,而不管其输入顺序如何。

The returned group is itself an iterator that shares the underlying iterable with groupby(). 返回的组本身是一个迭代器,它与groupby()共享底层可迭代对象。Because the source is shared, when the groupby() object is advanced, the previous group is no longer visible. 因为源是共享的,所以当groupby()对象处于高级状态时,上一个组不再可见。So, if that data is needed later, it should be stored as a list:因此,如果以后需要该数据,则应将其存储为列表:

groups = []
uniquekeys = []
data = sorted(data, key=keyfunc)
for k, g in groupby(data, keyfunc):
groups.append(list(g)) # Store group iterator as a list
uniquekeys.append(k)

groupby() is roughly equivalent to:大致相当于:

class groupby:
# [k for k, g in groupby('AAAABBBCCDAABBB')] --> A B C D A B
# [list(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D
def __init__(self, iterable, key=None):
if key is None:
key = lambda x: x
self.keyfunc = key
self.it = iter(iterable)
self.tgtkey = self.currkey = self.currvalue = object()
def __iter__(self):
return self
def __next__(self):
self.id = object()
while self.currkey == self.tgtkey:
self.currvalue = next(self.it) # Exit on StopIteration
self.currkey = self.keyfunc(self.currvalue)
self.tgtkey = self.currkey
return (self.currkey, self._grouper(self.tgtkey, self.id))
def _grouper(self, tgtkey, id):
while self.id is id and self.currkey == tgtkey:
yield self.currvalue
try:
self.currvalue = next(self.it)
except StopIteration:
return
self.currkey = self.keyfunc(self.currvalue)
itertools.islice(iterable, stop)
itertools.islice(iterable, start, stop[, step])

Make an iterator that returns selected elements from the iterable. 制作一个迭代器,从iterable返回选定的元素。If start is non-zero, then elements from the iterable are skipped until start is reached. 如果start为非零,则跳过可迭代对象中的元素,直到到达startAfterward, elements are returned consecutively unless step is set higher than one which results in items being skipped. 之后,元素将连续返回,除非step设置高于导致跳过项目的步骤。If stop is None, then iteration continues until the iterator is exhausted, if at all; otherwise, it stops at the specified position. 如果stopNone,则迭代继续,直到迭代器耗尽(如果有);否则,它将停止在指定位置。Unlike regular slicing, islice() does not support negative values for start, stop, or step. 与常规切片不同,islice()不支持startstopstep的负值。Can be used to extract related fields from data where the internal structure has been flattened (for example, a multi-line report may list a name field on every third line). 可用于从内部结构已扁平化的数据中提取相关字段(例如,多行报告可能每三行列出一个名称字段)。Roughly equivalent to:大致相当于:

def islice(iterable, *args):
# islice('ABCDEFG', 2) --> A B
# islice('ABCDEFG', 2, 4) --> C D
# islice('ABCDEFG', 2, None) --> C D E F G
# islice('ABCDEFG', 0, None, 2) --> A C E G
s = slice(*args)
start, stop, step = s.start or 0, s.stop or sys.maxsize, s.step or 1
it = iter(range(start, stop, step))
try:
nexti = next(it)
except StopIteration:
# Consume *iterable* up to the *start* position.
for i, element in zip(range(start), iterable):
pass
return
try:
for i, element in enumerate(iterable):
if i == nexti:
yield element
nexti = next(it)
except StopIteration:
# Consume to *stop*.
for i, element in zip(range(i + 1, stop), iterable):
pass

If start is None, then iteration starts at zero. 如果startNone,则迭代从零开始。If step is None, then the step defaults to one.如果stepNone,则步骤默认为一。

itertools.pairwise(iterable)

Return successive overlapping pairs taken from the input iterable.返回从输入iterable中获取的连续重叠对。

The number of 2-tuples in the output iterator will be one fewer than the number of inputs. 输出迭代器中的2元组数将比输入数少一个。It will be empty if the input iterable has fewer than two values.如果输入iterable的值少于两个,则它将为空。

Roughly equivalent to:大致相当于:

def pairwise(iterable):
# pairwise('ABCDEFG') --> AB BC CD DE EF FG
a, b = tee(iterable)
next(b, None)
return zip(a, b)

New in version 3.10.版本3.10中新增。

itertools.permutations(iterable, r=None)

Return successive r length permutations of elements in the iterable.返回iterable中元素的连续r长度置换。

If r is not specified or is None, then r defaults to the length of the iterable and all possible full-length permutations are generated.如果r未指定或无,则r默认为iterable的长度,并生成所有可能的全长置换。

The permutation tuples are emitted in lexicographic ordering according to the order of the input iterable. 置换元组根据输入iterable的顺序以字典序的形式发出。So, if the input iterable is sorted, the combination tuples will be produced in sorted order.因此,如果对输入iterable进行排序,则组合元组将按排序顺序生成。

Elements are treated as unique based on their position, not on their value. 元素根据其位置而不是价值被视为唯一。So if the input elements are unique, there will be no repeat values in each permutation.因此,如果输入元素是唯一的,则在每个置换中不会有重复值。

Roughly equivalent to:大致相当于:

def permutations(iterable, r=None):
# permutations('ABCD', 2) --> AB AC AD BA BC BD CA CB CD DA DB DC
# permutations(range(3)) --> 012 021 102 120 201 210
pool = tuple(iterable)
n = len(pool)
r = n if r is None else r
if r > n:
return
indices = list(range(n))
cycles = list(range(n, n-r, -1))
yield tuple(pool[i] for i in indices[:r])
while n:
for i in reversed(range(r)):
cycles[i] -= 1
if cycles[i] == 0:
indices[i:] = indices[i+1:] + indices[i:i+1]
cycles[i] = n - i
else:
j = cycles[i]
indices[i], indices[-j] = indices[-j], indices[i]
yield tuple(pool[i] for i in indices[:r])
break
else:
return

The code for permutations() can be also expressed as a subsequence of product(), filtered to exclude entries with repeated elements (those from the same position in the input pool):permutations()的代码也可以表示为product()的子序列,经过筛选以排除具有重复元素(输入池中相同位置的元素)的条目:

def permutations(iterable, r=None):
pool = tuple(iterable)
n = len(pool)
r = n if r is None else r
for indices in product(range(n), repeat=r):
if len(set(indices)) == r:
yield tuple(pool[i] for i in indices)

The number of items returned is n! / (n-r)! when 0 <= r <= n or zero when r > n.0 <= r <= n时返回的项目数为n! / (n-r)!,当r > n时为零。

itertools.product(*iterables, repeat=1)

Cartesian product of input iterables.输入项的笛卡尔乘积。

Roughly equivalent to nested for-loops in a generator expression. 大致相当于生成器表达式中的嵌套for循环。For example, product(A, B) returns the same as ((x,y) for x in A for y in B).例如,product(A, B)返回的值与((x,y) for x in A for y in B)的返回值相同。

The nested loops cycle like an odometer with the rightmost element advancing on every iteration. 嵌套循环像里程表一样循环,最右边的元素在每次迭代中前进。This pattern creates a lexicographic ordering so that if the input’s iterables are sorted, the product tuples are emitted in sorted order.该模式创建了一个字典排序,因此如果输入的可重用项被排序,则乘积元组将按排序顺序发出。

To compute the product of an iterable with itself, specify the number of repetitions with the optional repeat keyword argument. 要计算可迭代对象与自身的乘积,请使用可选的repeat关键字参数指定重复次数。For example, product(A, repeat=4) means the same as product(A, A, A, A).例如,product(A, repeat=4)表示与product(A, A, A, A)相同。

This function is roughly equivalent to the following code, except that the actual implementation does not build up intermediate results in memory:该函数大致相当于以下代码,但实际实现不会在内存中建立中间结果:

def product(*args, repeat=1):
# product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
# product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
pools = [tuple(pool) for pool in args] * repeat
result = [[]]
for pool in pools:
result = [x+[y] for x in result for y in pool]
for prod in result:
yield tuple(prod)

Before product() runs, it completely consumes the input iterables, keeping pools of values in memory to generate the products. product()运行之前,它会完全消耗输入项,将值池保留在内存中以生成产品。Accordingly, it is only useful with finite inputs.因此,它仅适用于有限输入。

itertools.repeat(object[, times])

Make an iterator that returns object over and over again. 制作一个迭代器,反复返回objectRuns indefinitely unless the times argument is specified. Used as argument to map() for invariant parameters to the called function. 除非指定了times参数,否则将无限期运行。用作将不变参数map()到被调用函数的参数。Also used with zip() to create an invariant part of a tuple record.还与zip()一起用于创建元组记录的不变部分。

Roughly equivalent to:大致相当于:

def repeat(object, times=None):
# repeat(10, 3) --> 10 10 10
if times is None:
while True:
yield object
else:
for i in range(times):
yield object

A common use for repeat is to supply a stream of constant values to map or zip:repeat的一个常见用法是向mapzip提供一个常量值流:

>>> list(map(pow, range(10), repeat(2)))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
itertools.starmap(function, iterable)

Make an iterator that computes the function using arguments obtained from the iterable. 制作一个迭代器,使用从iterable获得的参数计算函数。Used instead of map() when argument parameters are already grouped in tuples from a single iterable (the data has been “pre-zipped”). 当参数参数已从单个可迭代对象(数据已“预压缩”)分组为元组时,使用代替map()The difference between map() and starmap() parallels the distinction between function(a,b) and function(*c). map()starmap()之间的区别与function(a,b)function(*c)之间的区别类似。Roughly equivalent to:大致相当于:

def starmap(function, iterable):
# starmap(pow, [(2,5), (3,2), (10,3)]) --> 32 9 1000
for args in iterable:
yield function(*args)
itertools.takewhile(predicate, iterable)

Make an iterator that returns elements from the iterable as long as the predicate is true. 制作一个迭代器,只要谓词为true,它就会从iterable返回元素。Roughly equivalent to:大致相当于:

def takewhile(predicate, iterable):
# takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4
for x in iterable:
if predicate(x):
yield x
else:
break
itertools.tee(iterable, n=2)

Return n independent iterators from a single iterable.从单个可迭代对象返回n个独立迭代器。

The following Python code helps explain what tee does (although the actual implementation is more complex and uses only a single underlying FIFO queue).下面的Python代码有助于解释tee的功能(尽管实际实现更复杂,并且只使用单个底层先进先出队列)。

Roughly equivalent to:大致相当于:

def tee(iterable, n=2):
it = iter(iterable)
deques = [collections.deque() for i in range(n)]
def gen(mydeque):
while True:
if not mydeque: # when the local deque is empty
try:
newval = next(it) # fetch a new value and
except StopIteration:
return
for d in deques: # load it to all the deques
d.append(newval)
yield mydeque.popleft()
return tuple(gen(d) for d in deques)

Once tee() has made a split, the original iterable should not be used anywhere else; otherwise, the iterable could get advanced without the tee objects being informed.一旦tee()进行了拆分,原始可迭代对象就不应该在其他任何地方使用;否则,iterable可能会在不通知tee对象的情况下得到提升。

tee iterators are not threadsafe. tee迭代器不是线程安全的。A RuntimeError may be raised when using simultaneously iterators returned by the same tee() call, even if the original iterable is threadsafe.当同时使用同一个tee()调用返回的迭代器时,可能会引发RuntimeError,即使原始iterable是线程安全的。

This itertool may require significant auxiliary storage (depending on how much temporary data needs to be stored). 此itertool可能需要大量辅助存储(取决于需要存储多少临时数据)。In general, if one iterator uses most or all of the data before another iterator starts, it is faster to use list() instead of tee().通常,如果一个迭代器在另一个迭代器启动之前使用了大部分或全部数据,那么使用list()而不是tee()会更快。

itertools.zip_longest(*iterables, fillvalue=None)

Make an iterator that aggregates elements from each of the iterables. 制作一个迭代器,聚合每个ITerable中的元素。If the iterables are of uneven length, missing values are filled-in with fillvalue. 如果iterables的长度不均匀,则用fillvalue填充缺失的值。Iteration continues until the longest iterable is exhausted. 迭代将继续,直到最长的可迭代对象耗尽。Roughly equivalent to:大致相当于:

def zip_longest(*args, fillvalue=None):
# zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-
iterators = [iter(it) for it in args]
num_active = len(iterators)
if not num_active:
return
while True:
values = []
for i, it in enumerate(iterators):
try:
value = next(it)
except StopIteration:
num_active -= 1
if not num_active:
return
iterators[i] = repeat(fillvalue)
value = fillvalue
values.append(value)
yield tuple(values)

If one of the iterables is potentially infinite, then the zip_longest() function should be wrapped with something that limits the number of calls (for example islice() or takewhile()). 如果其中一个可迭代对象可能是无限的,那么zip_longest()函数应该用限制调用次数的东西包装(例如islice()takewhile()If not specified, fillvalue defaults to None.如果未指定,则fillvalue默认为None

Itertools RecipesItertools配方

This section shows recipes for creating an extended toolset using the existing itertools as building blocks.本节介绍了使用现有itertools作为构建块创建扩展工具集的方法。

Substantially all of these recipes and many, many others can be installed from the more-itertools project found on the Python Package Index:实际上,所有这些方法以及许多其他方法都可以从Python包索引中的更多itertools项目中安装:

pip install more-itertools

The extended tools offer the same high performance as the underlying toolset. 扩展工具提供了与底层工具集相同的高性能。The superior memory performance is kept by processing elements one at a time rather than bringing the whole iterable into memory all at once. 通过一次处理一个元素,而不是一次将整个iterable放入内存,可以保持优异的内存性能。Code volume is kept small by linking the tools together in a functional style which helps eliminate temporary variables. 通过以功能性风格将工具链接在一起,代码量保持较小,这有助于消除临时变量。High speed is retained by preferring “vectorized” building blocks over the use of for-loops and generators which incur interpreter overhead.与使用导致解释器开销的for循环和生成器相比,更倾向于使用“矢量化”构建块来保持高速。

def take(n, iterable):
"Return first n items of the iterable as a list"
return list(islice(iterable, n))
def prepend(value, iterator):
"Prepend a single value in front of an iterator"
# prepend(1, [2, 3, 4]) -> 1 2 3 4
return chain([value], iterator)

def tabulate(function, start=0):
"Return function(0), function(1), ..."
return map(function, count(start))

def tail(n, iterable):
"Return an iterator over the last n items"
# tail(3, 'ABCDEFG') --> E F G
return iter(collections.deque(iterable, maxlen=n))

def consume(iterator, n=None):
"Advance the iterator n-steps ahead. If n is None, consume entirely."
# Use functions that consume iterators at C speed.
if n is None:
# feed the entire iterator into a zero-length deque
collections.deque(iterator, maxlen=0)
else:
# advance to the empty slice starting at position n
next(islice(iterator, n, n), None)

def nth(iterable, n, default=None):
"Returns the nth item or a default value"
return next(islice(iterable, n, None), default)

def all_equal(iterable):
"Returns True if all the elements are equal to each other"
g = groupby(iterable)
return next(g, True) and not next(g, False)

def quantify(iterable, pred=bool):
"Count how many times the predicate is true"
return sum(map(pred, iterable))

def pad_none(iterable):
"""Returns the sequence elements and then returns None indefinitely.

Useful for emulating the behavior of the built-in map() function.
"""
return chain(iterable, repeat(None))

def ncycles(iterable, n):
"Returns the sequence elements n times"
return chain.from_iterable(repeat(tuple(iterable), n))

def dotproduct(vec1, vec2):
return sum(map(operator.mul, vec1, vec2))

def convolve(signal, kernel):
# See: https://betterexplained.com/articles/intuitive-convolution/
# convolve(data, [0.25, 0.25, 0.25, 0.25]) --> Moving average (blur)
# convolve(data, [1, -1]) --> 1st finite difference (1st derivative)
# convolve(data, [1, -2, 1]) --> 2nd finite difference (2nd derivative)
kernel = tuple(kernel)[::-1]
n = len(kernel)
window = collections.deque([0], maxlen=n) * n
for x in chain(signal, repeat(0, n-1)):
window.append(x)
yield sum(map(operator.mul, kernel, window))

def flatten(list_of_lists):
"Flatten one level of nesting"
return chain.from_iterable(list_of_lists)

def repeatfunc(func, times=None, *args):
"""Repeat calls to func with specified arguments.

Example: repeatfunc(random.random)
"""
if times is None:
return starmap(func, repeat(args))
return starmap(func, repeat(args, times))

def grouper(iterable, n, *, incomplete='fill', fillvalue=None):
"Collect data into non-overlapping fixed-length chunks or blocks"
# grouper('ABCDEFG', 3, fillvalue='x') --> ABC DEF Gxx
# grouper('ABCDEFG', 3, incomplete='strict') --> ABC DEF ValueError
# grouper('ABCDEFG', 3, incomplete='ignore') --> ABC DEF
args = [iter(iterable)] * n
if incomplete == 'fill':
return zip_longest(*args, fillvalue=fillvalue)
if incomplete == 'strict':
return zip(*args, strict=True)
if incomplete == 'ignore':
return zip(*args)
else:
raise ValueError('Expected fill, strict, or ignore')

def triplewise(iterable):
"Return overlapping triplets from an iterable"
# triplewise('ABCDEFG') -> ABC BCD CDE DEF EFG
for (a, _), (b, c) in pairwise(pairwise(iterable)):
yield a, b, c

def sliding_window(iterable, n):
# sliding_window('ABCDEFG', 4) -> ABCD BCDE CDEF DEFG
it = iter(iterable)
window = collections.deque(islice(it, n), maxlen=n)
if len(window) == n:
yield tuple(window)
for x in it:
window.append(x)
yield tuple(window)

def roundrobin(*iterables):
"roundrobin('ABC', 'D', 'EF') --> A D E B F C"
# Recipe credited to George Sakkis
num_active = len(iterables)
nexts = cycle(iter(it).__next__ for it in iterables)
while num_active:
try:
for next in nexts:
yield next()
except StopIteration:
# Remove the iterator we just exhausted from the cycle.
num_active -= 1
nexts = cycle(islice(nexts, num_active))

def partition(pred, iterable):
"Use a predicate to partition entries into false entries and true entries"
# partition(is_odd, range(10)) --> 0 2 4 6 8 and 1 3 5 7 9
t1, t2 = tee(iterable)
return filterfalse(pred, t1), filter(pred, t2)

def before_and_after(predicate, it):
""" Variant of takewhile() that allows complete
access to the remainder of the iterator.

>>> it = iter('ABCdEfGhI')
>>> all_upper, remainder = before_and_after(str.isupper, it)
>>> ''.join(all_upper)
'ABC'
>>> ''.join(remainder) # takewhile() would lose the 'd'
'dEfGhI'

Note that the first iterator must be fully
consumed before the second iterator can
generate valid results.
"""
it = iter(it)
transition = []
def true_iterator():
for elem in it:
if predicate(elem):
yield elem
else:
transition.append(elem)
return
def remainder_iterator():
yield from transition
yield from it
return true_iterator(), remainder_iterator()

def subslices(seq):
"Return all contiguous non-empty subslices of a sequence"
# subslices('ABCD') --> A AB ABC ABCD B BC BCD C CD D
slices = starmap(slice, combinations(range(len(seq) + 1), 2))
return map(operator.getitem, repeat(seq), slices)

def powerset(iterable):
"powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
s = list(iterable)
return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))

def unique_everseen(iterable, key=None):
"List unique elements, preserving order. Remember all elements ever seen."
# unique_everseen('AAAABBBCCDAABBB') --> A B C D
# unique_everseen('ABBCcAD', str.lower) --> A B C D
seen = set()
seen_add = seen.add
if key is None:
for element in filterfalse(seen.__contains__, iterable):
seen_add(element)
yield element
else:
for element in iterable:
k = key(element)
if k not in seen:
seen_add(k)
yield element

def unique_justseen(iterable, key=None):
"List unique elements, preserving order. Remember only the element just seen."
# unique_justseen('AAAABBBCCDAABBB') --> A B C D A B
# unique_justseen('ABBCcAD', str.lower) --> A B C A D
return map(next, map(operator.itemgetter(1), groupby(iterable, key)))

def iter_except(func, exception, first=None):
""" Call a function repeatedly until an exception is raised.

Converts a call-until-exception interface to an iterator interface.
Like builtins.iter(func, sentinel) but uses an exception instead
of a sentinel to end the loop.

Examples:
iter_except(functools.partial(heappop, h), IndexError) # priority queue iterator
iter_except(d.popitem, KeyError) # non-blocking dict iterator
iter_except(d.popleft, IndexError) # non-blocking deque iterator
iter_except(q.get_nowait, Queue.Empty) # loop over a producer Queue
iter_except(s.pop, KeyError) # non-blocking set iterator

"""
try:
if first is not None:
yield first() # For database APIs needing an initial cast to db.first()
while True:
yield func()
except exception:
pass

def first_true(iterable, default=False, pred=None):
"""Returns the first true value in the iterable.

If no true value is found, returns *default*

If *pred* is not None, returns the first item
for which pred(item) is true.

"""
# first_true([a,b,c], x) --> a or b or c or x
# first_true([a,b], x, f) --> a if f(a) else b if f(b) else x
return next(filter(pred, iterable), default)

def random_product(*args, repeat=1):
"Random selection from itertools.product(*args, **kwds)"
pools = [tuple(pool) for pool in args] * repeat
return tuple(map(random.choice, pools))

def random_permutation(iterable, r=None):
"Random selection from itertools.permutations(iterable, r)"
pool = tuple(iterable)
r = len(pool) if r is None else r
return tuple(random.sample(pool, r))

def random_combination(iterable, r):
"Random selection from itertools.combinations(iterable, r)"
pool = tuple(iterable)
n = len(pool)
indices = sorted(random.sample(range(n), r))
return tuple(pool[i] for i in indices)

def random_combination_with_replacement(iterable, r):
"Random selection from itertools.combinations_with_replacement(iterable, r)"
pool = tuple(iterable)
n = len(pool)
indices = sorted(random.choices(range(n), k=r))
return tuple(pool[i] for i in indices)

def nth_combination(iterable, r, index):
"Equivalent to list(combinations(iterable, r))[index]"
pool = tuple(iterable)
n = len(pool)
if r < 0 or r > n:
raise ValueError
c = 1
k = min(r, n-r)
for i in range(1, k+1):
c = c * (n - k + i) // i
if index < 0:
index += c
if index < 0 or index >= c:
raise IndexError
result = []
while r:
c, n, r = c*r//n, n-1, r-1
while index >= c:
index -= c
c, n = c*(n-r)//n, n-1
result.append(pool[-1-n])
return tuple(result)