itertools.md
1> **Источник:** https://python-all.ru/3.5/library/itertools.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 10.1. [`itertools`](https://python-all.ru/3.5/library/itertools.html#module-itertools) – Функции создания итераторов для эффективного перебора89---1011Этот модуль реализует ряд строительных блоков [итераторов](https://python-all.ru/3.5/glossary.html#term-iterator), вдохновлённых конструкциями из APL, Haskell и SML. Каждый из них переработан в форму, подходящую для Python.1213Модуль стандартизирует основной набор быстрых и эффективных по памяти инструментов, которые полезны сами по себе или в комбинации. Вместе они образуют «алгебру итераторов», позволяющую создавать специализированные инструменты кратко и эффективно на чистом Python.1415Например, SML предоставляет инструмент табуляции: `tabulate(f)`, который порождает последовательность `f(0), f(1), ...`. Того же эффекта можно достичь в Python скомбинировав [`map()`](https://python-all.ru/3.5/library/functions.html#map) и [`count()`](https://python-all.ru/3.5/library/itertools.html#itertools.count) для получения `map(f, count())`.1617Эти инструменты и их встроенные аналоги также хорошо работают с высокоскоростными функциями из модуля [`operator`](https://python-all.ru/3.5/library/operator.html#module-operator). Например, оператор умножения можно применить к двум векторам, чтобы получить эффективное скалярное произведение: `sum(map(operator.mul, vector1, vector2))`.1819**Бесконечные итераторы:**2021| Итератор | Аргументы | Результаты | Пример |22| --- | --- | --- | --- |23| [`count()`](https://python-all.ru/3.5/library/itertools.html#itertools.count) | start, \[step\] | start, start+step, start+2\*step, … | `count(10) --> 10 11 12 13 14 ...` |24| [`cycle()`](https://python-all.ru/3.5/library/itertools.html#itertools.cycle) | p | p0, p1, … plast, p0, p1, … | `cycle('ABCD') --> A B C D A B C D ...` |25| [`repeat()`](https://python-all.ru/3.5/library/itertools.html#itertools.repeat) | elem \[,n\] | elem, elem, elem, … бесконечно или до n раз | `repeat(10, 3) --> 10 10 10` |2627**Итераторы, завершающиеся по кратчайшей входной последовательности:**2829| Итератор | Аргументы | Результаты | Пример |30| --- | --- | --- | --- |31| [`accumulate()`](https://python-all.ru/3.5/library/itertools.html#itertools.accumulate) | p \[,func\] | p0, p0+p1, p0+p1+p2, … | `accumulate([1,2,3,4,5]) --> 1 3 6 10 15` |32| [`chain()`](https://python-all.ru/3.5/library/itertools.html#itertools.chain) | p, q, … | p0, p1, … plast, q0, q1, … | `chain('ABC', 'DEF') --> A B C D E F` |33| [`chain.from_iterable()`](https://python-all.ru/3.5/library/itertools.html#itertools.chain.from_iterable) | итерируемый объект | p0, p1, … plast, q0, q1, … | `chain.from_iterable(['ABC', 'DEF']) --> A B C D E F` |34| [`compress()`](https://python-all.ru/3.5/library/itertools.html#itertools.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` |35| [`dropwhile()`](https://python-all.ru/3.5/library/itertools.html#itertools.dropwhile) | pred, seq | seq\[n\], seq\[n+1\], начиная с момента, когда pred не выполняется | `dropwhile(lambda x: x<5, [1,4,6,4,1]) --> 6 4 1` |36| [`filterfalse()`](https://python-all.ru/3.5/library/itertools.html#itertools.filterfalse) | pred, seq | элементы seq, для которых pred(elem) ложно | `filterfalse(lambda x: x%2, range(10)) --> 0 2 4 6 8` |37| [`groupby()`](https://python-all.ru/3.5/library/itertools.html#itertools.groupby) | iterable\[, keyfunc\] | под-итераторы, сгруппированные по значению keyfunc(v) | |38| [`islice()`](https://python-all.ru/3.5/library/itertools.html#itertools.islice) | seq, \[start,\] stop \[, step\] | элементы из seq\[start:stop:step\] | `islice('ABCDEFG', 2, None) --> C D E F G` |39| [`starmap()`](https://python-all.ru/3.5/library/itertools.html#itertools.starmap) | func, seq | func(\*seq\[0\]), func(\*seq\[1\]), … | `starmap(pow, [(2,5), (3,2), (10,3)]) --> 32 9 1000` |40| [`takewhile()`](https://python-all.ru/3.5/library/itertools.html#itertools.takewhile) | pred, seq | seq\[0\], seq\[1\], пока pred не вернёт ложь | `takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4` |41| [`tee()`](https://python-all.ru/3.5/library/itertools.html#itertools.tee) | it, n | it1, it2, … itn разделяет один итератор на n | |42| [`zip_longest()`](https://python-all.ru/3.5/library/itertools.html#itertools.zip_longest) | p, q, … | (p\[0\], q\[0\]), (p\[1\], q\[1\]), … | `zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-` |4344**Комбинаторные генераторы:**4546| Итератор | Аргументы | Результаты |47| --- | --- | --- |48| [`product()`](https://python-all.ru/3.5/library/itertools.html#itertools.product) | p, q, … \[repeat=1\] | декартово произведение, эквивалентно вложенному циклу for |49| [`permutations()`](https://python-all.ru/3.5/library/itertools.html#itertools.permutations) | p\[, r\] | кортежи длиной r, все возможные перестановки, без повторяющихся элементов |50| [`combinations()`](https://python-all.ru/3.5/library/itertools.html#itertools.combinations) | p, r | кортежи длиной r, в отсортированном порядке, без повторяющихся элементов |51| [`combinations_with_replacement()`](https://python-all.ru/3.5/library/itertools.html#itertools.combinations_with_replacement) | p, r | кортежи длиной r, в отсортированном порядке, с повторяющимися элементами |52| `product('ABCD', repeat=2)` | | `AA AB AC AD BA BB BC BD CA CB CC CD DA DB DC DD` |53| `permutations('ABCD', 2)` | | `AB AC AD BA BC BD CA CB CD DA DB DC` |54| `combinations('ABCD', 2)` | | `AB AC AD BC BD CD` |55| `combinations_with_replacement('ABCD', 2)` | | `AA AB AC AD BB BC BD CC CD DD` |5657## 10.1.1. Функции itertool5859Следующие функции модуля создают и возвращают итераторы. Некоторые из них порождают потоки бесконечной длины, поэтому обращаться к ним следует только с помощью функций или циклов, которые обрывают поток.6061#### `itertools.accumulate(iterable[, func])`6263Создаёт итератор, возвращающий накопленные суммы или накопленные результаты других бинарных функций (задаваемых необязательным аргументом *func*). Если *func* указана, это должна быть функция двух аргументов. Элементы входного *iterable* могут быть любого типа, который может быть принят в качестве аргумента *func*. (Например, при стандартной операции сложения элементы могут быть любого складываемого типа, включая [`Decimal`](https://python-all.ru/3.5/library/decimal.html#decimal.Decimal) или [`Fraction`](https://python-all.ru/3.5/library/fractions.html#fractions.Fraction).) Если входной итератор пуст, выходной итератор также будет пуст.6465Примерно эквивалентно:6667```python68def accumulate(iterable, func=operator.add):69 'Return running totals'70 # accumulate([1,2,3,4,5]) --> 1 3 6 10 1571 # accumulate([1,2,3,4,5], operator.mul) --> 1 2 6 24 12072 it = iter(iterable)73 try:74 total = next(it)75 except StopIteration:76 return77 yield total78 for element in it:79 total = func(total, element)80 yield total81```8283У аргумента *func* есть несколько применений. Его можно установить в [`min()`](https://python-all.ru/3.5/library/functions.html#min) для текущего минимума, [`max()`](https://python-all.ru/3.5/library/functions.html#max) для текущего максимума или [`operator.mul()`](https://python-all.ru/3.5/library/operator.html#operator.mul) для текущего произведения. Таблицы амортизации можно построить, накапливая проценты и применяя платежи. [Рекуррентные соотношения](https://python-all.ru/3.5/library/itertools.html) первого порядка можно смоделировать, передав начальное значение в итерируемом объекте и используя только накопленную сумму в аргументе *func*:8485```python86>>> data = [3, 4, 6, 2, 1, 9, 0, 7, 5, 8]87>>> list(accumulate(data, operator.mul)) # текущее произведение88[3, 12, 72, 144, 144, 1296, 0, 0, 0, 0]89>>> list(accumulate(data, max)) # текущий максимум90[3, 4, 6, 6, 6, 9, 9, 9, 9, 9]9192# Amortize a 5% loan of 1000 with 4 annual payments of 9093>>> cashflows = [1000, -90, -90, -90, -90]94>>> list(accumulate(cashflows, lambda bal, pmt: bal*1.05 + pmt))95[1000, 960.0, 918.0, 873.9000000000001, 827.5950000000001]9697# Chaotic recurrence relation https://en.wikipedia.org/wiki/Logistic_map98>>> logistic_map = lambda x, _: r * x * (1 - x)99>>> r = 3.8100>>> x0 = 0.4101>>> inputs = repeat(x0, 36) # используется только начальное значение102>>> [format(x, '.2f') for x in accumulate(inputs, logistic_map)]103['0.40', '0.91', '0.30', '0.81', '0.60', '0.92', '0.29', '0.79', '0.63',104 '0.88', '0.39', '0.90', '0.33', '0.84', '0.52', '0.95', '0.18', '0.57',105 '0.93', '0.25', '0.71', '0.79', '0.63', '0.88', '0.39', '0.91', '0.32',106 '0.83', '0.54', '0.95', '0.20', '0.60', '0.91', '0.30', '0.80', '0.60']107```108109См. [`functools.reduce()`](https://python-all.ru/3.5/library/functools.html#functools.reduce) – похожая функция, возвращающая только итоговое накопленное значение.110111Новое в версии 3.2.112113Изменено в версии 3.3: Добавлен необязательный параметр *func*.114115#### `itertools.chain(*iterables)`116117Создаёт итератор, который возвращает элементы из первого итерируемого объекта, пока он не будет исчерпан, затем переходит к следующему, пока все итерируемые объекты не будут исчерпаны. Используется для объединения последовательностей в одну. Приблизительный эквивалент:118119```python120def chain(*iterables):121 # chain('ABC', 'DEF') --> A B C D E F122 for it in iterables:123 for element in it:124 yield element125```126127#### `classmethod chain.from_iterable(iterable)`128129Альтернативный конструктор для [`chain()`](https://python-all.ru/3.5/library/itertools.html#itertools.chain). Получает цепочку входных данных из одного аргумента iterable, который вычисляется лениво. Примерная реализация:130131```python132def from_iterable(iterables):133 # chain.from_iterable(['ABC', 'DEF']) --> A B C D E F134 for it in iterables:135 for element in it:136 yield element137```138139#### `itertools.combinations(iterable, r)`140141Возвращает подпоследовательности элементов длины *r* из входного *iterable*.142143Комбинации выдаются в лексикографическом порядке. Таким образом, если входной *итерируемый объект* отсортирован, кортежи комбинаций будут созданы в отсортированном порядке.144145Элементы считаются уникальными на основе их позиции, а не значения. Поэтому если входные элементы уникальны, то в каждой комбинации не будет повторяющихся значений.146147Примерно эквивалентно:148149```python150def combinations(iterable, r):151 # combinations('ABCD', 2) --> AB AC AD BC BD CD152 # combinations(range(4), 3) --> 012 013 023 123153 pool = tuple(iterable)154 n = len(pool)155 if r > n:156 return157 indices = list(range(r))158 yield tuple(pool[i] for i in indices)159 while True:160 for i in reversed(range(r)):161 if indices[i] != i + n - r:162 break163 else:164 return165 indices[i] += 1166 for j in range(i+1, r):167 indices[j] = indices[j-1] + 1168 yield tuple(pool[i] for i in indices)169```170171Код для [`combinations()`](https://python-all.ru/3.5/library/itertools.html#itertools.combinations) можно также выразить как подпоследовательность [`permutations()`](https://python-all.ru/3.5/library/itertools.html#itertools.permutations) после фильтрации записей, где элементы не находятся в отсортированном порядке (согласно их позиции во входном пуле):172173```python174def combinations(iterable, r):175 pool = tuple(iterable)176 n = len(pool)177 for indices in permutations(range(n), r):178 if sorted(indices) == list(indices):179 yield tuple(pool[i] for i in indices)180```181182Количество возвращаемых элементов равно `n! / r! / (n-r)!`, когда `0 <= r <= n`, или нулю, когда `r > n`.183184#### `itertools.combinations_with_replacement(iterable, r)`185186Возвращает подпоследовательности элементов длины *r* из входного *iterable*, допуская повторение отдельных элементов.187188Комбинации выдаются в лексикографическом порядке. Таким образом, если входной *итерируемый объект* отсортирован, кортежи комбинаций будут созданы в отсортированном порядке.189190Элементы считаются уникальными по их позиции, а не по значению. Поэтому если входные элементы уникальны, сгенерированные комбинации также будут уникальны.191192Примерно эквивалентно:193194```python195def combinations_with_replacement(iterable, r):196 # combinations_with_replacement('ABC', 2) --> AA AB AC BB BC CC197 pool = tuple(iterable)198 n = len(pool)199 if not n and r:200 return201 indices = [0] * r202 yield tuple(pool[i] for i in indices)203 while True:204 for i in reversed(range(r)):205 if indices[i] != n - 1:206 break207 else:208 return209 indices[i:] = [indices[i] + 1] * (r - i)210 yield tuple(pool[i] for i in indices)211```212213Код для [`combinations_with_replacement()`](https://python-all.ru/3.5/library/itertools.html#itertools.combinations_with_replacement) можно также выразить как подпоследовательность [`product()`](https://python-all.ru/3.5/library/itertools.html#itertools.product) после фильтрации записей, где элементы не находятся в отсортированном порядке (согласно их позиции во входном пуле):214215```python216def combinations_with_replacement(iterable, r):217 pool = tuple(iterable)218 n = len(pool)219 for indices in product(range(n), repeat=r):220 if sorted(indices) == list(indices):221 yield tuple(pool[i] for i in indices)222```223224Количество возвращаемых элементов равно `(n+r-1)! / r! / (n-1)!`, когда `n > 0`.225226Новое в версии 3.1.227228#### `itertools.compress(data, selectors)`229230Создаёт итератор, который фильтрует элементы из *data*, возвращая только те, для которых в *selectors* есть соответствующий элемент, вычисляемый как `True`. Останавливается, когда исчерпан либо итерабельный объект *data*, либо *selectors*. Примерно эквивалентен:231232```python233def compress(data, selectors):234 # compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F235 return (d for d, s in zip(data, selectors) if s)236```237238Новое в версии 3.1.239240#### `itertools.count(start=0, step=1)`241242Создаёт итератор, возвращающий равномерно распределённые значения, начиная с числа *start*. Часто используется как аргумент для [`map()`](https://python-all.ru/3.5/library/functions.html#map) для генерации последовательных точек данных. Также используется с [`zip()`](https://python-all.ru/3.5/library/functions.html#zip) для добавления порядковых номеров. Примерно эквивалентен:243244```python245def count(start=0, step=1):246 # count(10) --> 10 11 12 13 14 ...247 # count(2.5, 0.5) -> 2.5 3.0 3.5 ...248 n = start249 while True:250 yield n251 n += step252```253254При подсчёте с числами с плавающей запятой иногда можно добиться лучшей точности, заменив код на мультипликативный, например: `(start + step * i for i in count())`.255256Изменено в версии 3.1: Добавлен аргумент *step* и разрешены нецелые аргументы.257258#### `itertools.cycle(iterable)`259260Создаёт итератор, возвращающий элементы из итерабельного объекта и сохраняющий копию каждого. Когда итерабельный объект исчерпан, возвращает элементы из сохранённой копии. Повторяется бесконечно. Примерно эквивалентен:261262```python263def cycle(iterable):264 # cycle('ABCD') --> A B C D A B C D A B C D ...265 saved = []266 for element in iterable:267 yield element268 saved.append(element)269 while saved:270 for element in saved:271 yield element272```273274Примечание: этот элемент набора инструментов может потребовать значительного дополнительного хранилища (в зависимости от длины итерабельного объекта).275276#### `itertools.dropwhile(predicate, iterable)`277278Создаёт итератор, который отбрасывает элементы из итерабельного объекта, пока предикат истинен; после этого возвращает каждый элемент. Примечание: итератор не выдаёт *никакого* вывода, пока предикат впервые не станет ложным, поэтому время запуска может быть большим. Примерно эквивалентен:279280```python281def dropwhile(predicate, iterable):282 # dropwhile(lambda x: x<5, [1,4,6,4,1]) --> 6 4 1283 iterable = iter(iterable)284 for x in iterable:285 if not predicate(x):286 yield x287 break288 for x in iterable:289 yield x290```291292#### `itertools.filterfalse(predicate, iterable)`293294Создаёт итератор, который фильтрует элементы из итерируемого объекта, возвращая только те, для которых предикат равен `False`. Если *предикат* равен `None`, возвращает элементы, которые являются ложными. Примерно эквивалентно:295296```python297def filterfalse(predicate, iterable):298 # filterfalse(lambda x: x%2, range(10)) --> 0 2 4 6 8299 if predicate is None:300 predicate = bool301 for x in iterable:302 if not predicate(x):303 yield x304```305306#### `itertools.groupby(iterable, key=None)`307308Make an iterator that returns consecutive keys and groups from the *iterable*. The *key* is a function computing a key value for each element. If not specified or is `None`, *key* defaults to an identity function and returns the element unchanged. Generally, the iterable needs to already be sorted on the same key function.309310Работа [`groupby()`](https://python-all.ru/3.5/library/itertools.html#itertools.groupby) аналогична фильтру `uniq` в Unix. Она создает разрыв или новую группу каждый раз, когда изменяется значение ключевой функции (поэтому обычно необходимо отсортировать данные с помощью той же ключевой функции). Такое поведение отличается от SQL GROUP BY, которая объединяет общие элементы независимо от порядка их ввода.311312Возвращаемая группа сама является итератором, который использует общий исходный итерируемый объект с [`groupby()`](https://python-all.ru/3.5/library/itertools.html#itertools.groupby). Поскольку источник общий, при продвижении объекта [`groupby()`](https://python-all.ru/3.5/library/itertools.html#itertools.groupby) предыдущая группа перестает быть видимой. Поэтому, если эти данные понадобятся позже, их следует сохранить в виде списка:313314```python315groups = []316uniquekeys = []317data = sorted(data, key=keyfunc)318for k, g in groupby(data, keyfunc):319 groups.append(list(g)) # Сохранить групповой итератор как список320 uniquekeys.append(k)321```322323[`groupby()`](https://python-all.ru/3.5/library/itertools.html#itertools.groupby) примерно эквивалентно:324325```python326class groupby:327 # [k for k, g in groupby('AAAABBBCCDAABBB')] --> A B C D A B328 # [list(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D329 def __init__(self, iterable, key=None):330 if key is None:331 key = lambda x: x332 self.keyfunc = key333 self.it = iter(iterable)334 self.tgtkey = self.currkey = self.currvalue = object()335 def __iter__(self):336 return self337 def __next__(self):338 while self.currkey == self.tgtkey:339 self.currvalue = next(self.it) # Выход при StopIteration340 self.currkey = self.keyfunc(self.currvalue)341 self.tgtkey = self.currkey342 return (self.currkey, self._grouper(self.tgtkey))343 def _grouper(self, tgtkey):344 while self.currkey == tgtkey:345 yield self.currvalue346 try:347 self.currvalue = next(self.it)348 except StopIteration:349 return350 self.currkey = self.keyfunc(self.currvalue)351```352353#### `itertools.islice(iterable, stop)`354355#### `itertools.islice(iterable, start, stop[, step])`356357Создаёт итератор, который возвращает выбранные элементы из итерируемого объекта. Если *start* не равен нулю, то элементы из итерируемого объекта пропускаются до достижения start. Затем элементы возвращаются последовательно, если только *step* не установлен больше единицы, что приводит к пропуску элементов. Если *stop* равен `None`, то итерация продолжается до тех пор, пока итератор не будет исчерпан, если вообще; в противном случае она останавливается на указанной позиции. В отличие от обычной срезки, [`islice()`](https://python-all.ru/3.5/library/itertools.html#itertools.islice) не поддерживает отрицательные значения для *start*, *stop* или *step*. Может использоваться для извлечения связанных полей из данных, где внутренняя структура была уплощена (например, многострочный отчёт может содержать поле имени на каждой третьей строке). Примерно эквивалентно:358359```python360def islice(iterable, *args):361 # islice('ABCDEFG', 2) --> A B362 # islice('ABCDEFG', 2, 4) --> C D363 # islice('ABCDEFG', 2, None) --> C D E F G364 # islice('ABCDEFG', 0, None, 2) --> A C E G365 s = slice(*args)366 it = iter(range(s.start or 0, s.stop or sys.maxsize, s.step or 1))367 try:368 nexti = next(it)369 except StopIteration:370 return371 for i, element in enumerate(iterable):372 if i == nexti:373 yield element374 nexti = next(it)375```376377Если *start* равен `None`, то итерация начинается с нуля. Если *step* равен `None`, то шаг по умолчанию равен единице.378379#### `itertools.permutations(iterable, r=None)`380381Возвращает последовательные перестановки длины *r* элементов из *iterable*.382383Если *r* не указан или равен `None`, то *r* по умолчанию равен длине *iterable* и генерируются все возможные перестановки полной длины.384385Перестановки выдаются в лексикографическом порядке. Таким образом, если входной *итерируемый объект* отсортирован, кортежи перестановок будут созданы в отсортированном порядке.386387Элементы считаются уникальными на основе их позиции, а не значения. Поэтому если входные элементы уникальны, то в каждой перестановке не будет повторяющихся значений.388389Примерно эквивалентно:390391```python392def permutations(iterable, r=None):393 # permutations('ABCD', 2) --> AB AC AD BA BC BD CA CB CD DA DB DC394 # permutations(range(3)) --> 012 021 102 120 201 210395 pool = tuple(iterable)396 n = len(pool)397 r = n if r is None else r398 if r > n:399 return400 indices = list(range(n))401 cycles = list(range(n, n-r, -1))402 yield tuple(pool[i] for i in indices[:r])403 while n:404 for i in reversed(range(r)):405 cycles[i] -= 1406 if cycles[i] == 0:407 indices[i:] = indices[i+1:] + indices[i:i+1]408 cycles[i] = n - i409 else:410 j = cycles[i]411 indices[i], indices[-j] = indices[-j], indices[i]412 yield tuple(pool[i] for i in indices[:r])413 break414 else:415 return416```417418Код для [`permutations()`](https://python-all.ru/3.5/library/itertools.html#itertools.permutations) также можно выразить как подпоследовательность [`product()`](https://python-all.ru/3.5/library/itertools.html#itertools.product), отфильтрованную для исключения записей с повторяющимися элементами (тех, которые находятся на одной и той же позиции во входном пуле):419420```python421def permutations(iterable, r=None):422 pool = tuple(iterable)423 n = len(pool)424 r = n if r is None else r425 for indices in product(range(n), repeat=r):426 if len(set(indices)) == r:427 yield tuple(pool[i] for i in indices)428```429430Количество возвращаемых элементов равно `n! / (n-r)!`, когда `0 <= r <= n`, или нулю, когда `r > n`.431432#### `itertools.product(*iterables, repeat=1)`433434Декартово произведение входных итерируемых объектов.435436Примерно эквивалентно вложенным циклам for в генераторном выражении. Например, `product(A, B)` возвращает то же, что и `((x,y) for x in A for y in B)`.437438Вложенные циклы работают как одометр: самый правый элемент увеличивается на каждой итерации. Этот шаблон создает лексикографический порядок, так что если входные итерируемые объекты отсортированы, кортежи произведения выдаются в отсортированном порядке.439440Чтобы вычислить произведение итерируемого объекта на самого себя, укажите количество повторений с помощью необязательного именованного аргумента *repeat*. Например, `product(A, repeat=4)` эквивалентно `product(A, A, A, A)`.441442Эта функция примерно эквивалентна следующему коду, за исключением того, что реальная реализация не накапливает промежуточные результаты в памяти:443444```python445def product(*args, repeat=1):446 # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy447 # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111448 pools = [tuple(pool) for pool in args] * repeat449 result = [[]]450 for pool in pools:451 result = [x+[y] for x in result for y in pool]452 for prod in result:453 yield tuple(prod)454```455456#### `itertools.repeat(object[, times])`457458Создаёт итератор, который снова и снова возвращает *object*. Выполняется бесконечно, если не указан аргумент *times*. Используется как аргумент [`map()`](https://python-all.ru/3.5/library/functions.html#map) для инвариантных параметров вызываемой функции. Также используется с [`zip()`](https://python-all.ru/3.5/library/functions.html#zip) для создания инвариантной части кортежной записи.459460Примерно эквивалентно:461462```python463def repeat(object, times=None):464 # repeat(10, 3) --> 10 10 10465 if times is None:466 while True:467 yield object468 else:469 for i in range(times):470 yield object471```472473Обычное применение *repeat* – передача потока постоянных значений в *map* или *zip*:474475```python476>>> list(map(pow, range(10), repeat(2)))477[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]478```479480#### `itertools.starmap(function, iterable)`481482Создаёт итератор, который вычисляет функцию, используя аргументы, полученные из итерируемого объекта. Используется вместо [`map()`](https://python-all.ru/3.5/library/functions.html#map), когда параметры аргументов уже сгруппированы в кортежи из одного итерируемого объекта (данные были «предварительно сжаты»). Разница между [`map()`](https://python-all.ru/3.5/library/functions.html#map) и [`starmap()`](https://python-all.ru/3.5/library/itertools.html#itertools.starmap) параллельна различию между `function(a,b)` и `function(*c)`. Примерно эквивалентно:483484```python485def starmap(function, iterable):486 # starmap(pow, [(2,5), (3,2), (10,3)]) --> 32 9 1000487 for args in iterable:488 yield function(*args)489```490491#### `itertools.takewhile(predicate, iterable)`492493Создаёт итератор, возвращающий элементы из итерируемого объекта, пока предикат истинен. Приблизительно эквивалентно:494495```python496def takewhile(predicate, iterable):497 # takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4498 for x in iterable:499 if predicate(x):500 yield x501 else:502 break503```504505#### `itertools.tee(iterable, n=2)`506507Возвращает *n* независимых итераторов из одного итерируемого объекта. Примерно эквивалентно:508509```python510def tee(iterable, n=2):511 it = iter(iterable)512 deques = [collections.deque() for i in range(n)]513 def gen(mydeque):514 while True:515 if not mydeque: # когда локальная deque пуста516 try:517 newval = next(it) # извлечь новое значение и518 except StopIteration:519 return520 for d in deques: # загрузить его во все двусторонние очереди521 d.append(newval)522 yield mydeque.popleft()523 return tuple(gen(d) for d in deques)524```525526После того как [`tee()`](https://python-all.ru/3.5/library/itertools.html#itertools.tee) выполнил разделение, исходный *итерируемый объект* не следует использовать где-либо ещё; в противном случае *итерируемый объект* может продвинуться без уведомления объектов tee.527528Этот инструмент итерации может потребовать значительного вспомогательного хранилища (в зависимости от объёма временных данных, которые необходимо сохранить). В общем случае, если один итератор использует большую часть или все данные до того, как запустится другой итератор, быстрее использовать [`list()`](https://python-all.ru/3.5/library/stdtypes.html#list) вместо [`tee()`](https://python-all.ru/3.5/library/itertools.html#itertools.tee).529530#### `itertools.zip_longest(*iterables, fillvalue=None)`531532Создаёт итератор, который агрегирует элементы из каждого из итерируемых объектов. Если итерируемые объекты имеют разную длину, недостающие значения заполняются с помощью *fillvalue*. Итерация продолжается до тех пор, пока самый длинный итерируемый объект не будет исчерпан. Приблизительно эквивалентно:533534```python535class ZipExhausted(Exception):536 pass537538def zip_longest(*args, **kwds):539 # zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-540 fillvalue = kwds.get('fillvalue')541 counter = len(args) - 1542 def sentinel():543 nonlocal counter544 if not counter:545 raise ZipExhausted546 counter -= 1547 yield fillvalue548 fillers = repeat(fillvalue)549 iterators = [chain(it, sentinel(), fillers) for it in args]550 try:551 while iterators:552 yield tuple(map(next, iterators))553 except ZipExhausted:554 pass555```556557Если один из итерируемых объектов потенциально бесконечен, то функцию [`zip_longest()`](https://python-all.ru/3.5/library/itertools.html#itertools.zip_longest) следует обернуть чем-то, что ограничивает количество вызовов (например, [`islice()`](https://python-all.ru/3.5/library/itertools.html#itertools.islice) или [`takewhile()`](https://python-all.ru/3.5/library/itertools.html#itertools.takewhile)). Если не указано, *fillvalue* по умолчанию равен `None`.558559## 10.1.2. Рецепты itertools560561В этом разделе представлены рецепты для создания расширенного набора инструментов с использованием существующих itertools в качестве строительных блоков.562563Расширенные инструменты обеспечивают такую же высокую производительность, как и базовый набор инструментов. Превосходная производительность по памяти достигается за счёт обработки элементов по одному, а не загрузки всего итерируемого объекта в память сразу. Объём кода остаётся небольшим благодаря связыванию инструментов в функциональном стиле, что помогает избавиться от временных переменных. Высокая скорость сохраняется за счёт предпочтения «векторизованных» строительных блоков вместо использования циклов for и [генераторов](https://python-all.ru/3.5/glossary.html#term-generator), которые создают накладные расходы интерпретатора.564565```python566def take(n, iterable):567 "Return first n items of the iterable as a list"568 return list(islice(iterable, n))569570def tabulate(function, start=0):571 "Return function(0), function(1), ..."572 return map(function, count(start))573574def tail(n, iterable):575 "Return an iterator over the last n items"576 # tail(3, 'ABCDEFG') --> E F G577 return iter(collections.deque(iterable, maxlen=n))578579def consume(iterator, n):580 "Advance the iterator n-steps ahead. If n is none, consume entirely."581 # Используйте функции, потребляющие итераторы на скорости C.582 if n is None:583 # передать весь итератор в deque нулевой длины584 collections.deque(iterator, maxlen=0)585 else:586 # перейти к пустому срезу начиная с позиции n587 next(islice(iterator, n, n), None)588589def nth(iterable, n, default=None):590 "Returns the nth item or a default value"591 return next(islice(iterable, n, None), default)592593def all_equal(iterable):594 "Returns True if all the elements are equal to each other"595 g = groupby(iterable)596 return next(g, True) and not next(g, False)597598def quantify(iterable, pred=bool):599 "Count how many times the predicate is true"600 return sum(map(pred, iterable))601602def padnone(iterable):603 """Возвращает элементы последовательности, а затем бесконечно возвращает None.604605 Полезно для эмуляции поведения встроенной функции map().606 """607 return chain(iterable, repeat(None))608609def ncycles(iterable, n):610 "Returns the sequence elements n times"611 return chain.from_iterable(repeat(tuple(iterable), n))612613def dotproduct(vec1, vec2):614 return sum(map(operator.mul, vec1, vec2))615616def flatten(listOfLists):617 "Flatten one level of nesting"618 return chain.from_iterable(listOfLists)619620def repeatfunc(func, times=None, *args):621 """Повторяет вызовы func с указанными аргументами.622623 Пример: repeatfunc(random.random)624 """625 if times is None:626 return starmap(func, repeat(args))627 return starmap(func, repeat(args, times))628629def pairwise(iterable):630 "s -> (s0,s1), (s1,s2), (s2, s3), ..."631 a, b = tee(iterable)632 next(b, None)633 return zip(a, b)634635def grouper(iterable, n, fillvalue=None):636 "Collect data into fixed-length chunks or blocks"637 # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"638 args = [iter(iterable)] * n639 return zip_longest(*args, fillvalue=fillvalue)640641def roundrobin(*iterables):642 "roundrobin('ABC', 'D', 'EF') --> A D E B F C"643 # Автор рецепта – Джордж Саккис644 pending = len(iterables)645 nexts = cycle(iter(it).__next__ for it in iterables)646 while pending:647 try:648 for next in nexts:649 yield next()650 except StopIteration:651 pending -= 1652 nexts = cycle(islice(nexts, pending))653654def partition(pred, iterable):655 'Use a predicate to partition entries into false entries and true entries'656 # partition(is_odd, range(10)) --> 0 2 4 6 8 и 1 3 5 7 9657 t1, t2 = tee(iterable)658 return filterfalse(pred, t1), filter(pred, t2)659660def powerset(iterable):661 "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"662 s = list(iterable)663 return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))664665def unique_everseen(iterable, key=None):666 "List unique elements, preserving order. Remember all elements ever seen."667 # unique_everseen('AAAABBBCCDAABBB') --> A B C D668 # unique_everseen('ABBCcAD', str.lower) --> A B C D669 seen = set()670 seen_add = seen.add671 if key is None:672 for element in filterfalse(seen.__contains__, iterable):673 seen_add(element)674 yield element675 else:676 for element in iterable:677 k = key(element)678 if k not in seen:679 seen_add(k)680 yield element681682def unique_justseen(iterable, key=None):683 "List unique elements, preserving order. Remember only the element just seen."684 # unique_justseen('AAAABBBCCDAABBB') --> A B C D A B685 # unique_justseen('ABBCcAD', str.lower) --> A B C A D686 return map(next, map(itemgetter(1), groupby(iterable, key)))687688def iter_except(func, exception, first=None):689 """ Повторно вызывает функцию до возникновения исключения.690691 Преобразует интерфейс вызова до исключения в интерфейс итератора.692 Как builtins.iter(func, sentinel), но использует исключение вместо693 сигнального значения для завершения цикла.694695 Примеры:696 iter_except(functools.partial(heappop, h), IndexError) # итератор очереди с приоритетом697 iter_except(d.popitem, KeyError) # итератор словаря без блокировки698 iter_except(d.popleft, IndexError) # итератор дека без блокировки699 iter_except(q.get_nowait, Queue.Empty) # цикл по очереди производителя700 iter_except(s.pop, KeyError) # итератор множества без блокировки701702 """703 try:704 if first is not None:705 yield first() # Для API баз данных, требующих первоначального приведения к db.first()706 while True:707 yield func()708 except exception:709 pass710711def first_true(iterable, default=False, pred=None):712 """Возвращает первое истинное значение в итерируемом объекте.713714 Если истинное значение не найдено, возвращает *default*715716 Если *pred* не равен None, возвращает первый элемент717 для которого pred(item) истинно.718719 """720 # first_true([a,b,c], x) --> a или b или c или x721 # first_true([a,b], x, f) --> a если f(a) иначе b если f(b) иначе x722 return next(filter(pred, iterable), default)723724def random_product(*args, repeat=1):725 "Random selection from itertools.product(*args, **kwds)"726 pools = [tuple(pool) for pool in args] * repeat727 return tuple(random.choice(pool) for pool in pools)728729def random_permutation(iterable, r=None):730 "Random selection from itertools.permutations(iterable, r)"731 pool = tuple(iterable)732 r = len(pool) if r is None else r733 return tuple(random.sample(pool, r))734735def random_combination(iterable, r):736 "Random selection from itertools.combinations(iterable, r)"737 pool = tuple(iterable)738 n = len(pool)739 indices = sorted(random.sample(range(n), r))740 return tuple(pool[i] for i in indices)741742def random_combination_with_replacement(iterable, r):743 "Random selection from itertools.combinations_with_replacement(iterable, r)"744 pool = tuple(iterable)745 n = len(pool)746 indices = sorted(random.randrange(n) for i in range(r))747 return tuple(pool[i] for i in indices)748```749750Обратите внимание: многие из приведённых выше рецептов можно оптимизировать, заменив глобальные поиски локальными переменными, определёнными как значения по умолчанию. Например, рецепт *dotproduct* можно записать так:751752```python753def dotproduct(vec1, vec2, sum=sum, map=map, mul=operator.mul):754 return sum(map(mul, vec1, vec2))755```756