itertools.md
1> **Источник:** https://python-all.ru/3.4/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.4/library/itertools.html#module-itertools) – функции, создающие итераторы для эффективного перебора89Этот модуль реализует ряд строительных блоков [*итераторов*](https://python-all.ru/3.4/glossary.html#term-iterator), вдохновлённых конструкциями из APL, Haskell и SML. Каждый из них переработан в форму, подходящую для Python.1011Модуль стандартизирует основной набор быстрых и эффективных по памяти инструментов, которые полезны сами по себе или в комбинации. Вместе они образуют «алгебру итераторов», позволяющую создавать специализированные инструменты кратко и эффективно на чистом Python.1213Например, в SML есть инструмент табуляции: `tabulate(f)`, который создаёт последовательность `f(0), f(1), ...`. Того же эффекта в Python можно добиться, объединив [`map()`](https://python-all.ru/3.4/library/functions.html#map) и [`count()`](https://python-all.ru/3.4/library/itertools.html#itertools.count), чтобы получить `map(f, count())`.1415Эти инструменты и их встроенные аналоги также хорошо работают с высокоскоростными функциями из модуля [`operator`](https://python-all.ru/3.4/library/operator.html#module-operator). Например, оператор умножения можно применить к двум векторам, чтобы вычислить эффективное скалярное произведение: `sum(map(operator.mul, vector1, vector2))`.1617**Бесконечные итераторы:**1819| Итератор | Аргументы | Результаты | Пример |20| --- | --- | --- | --- |21| [`count()`](https://python-all.ru/3.4/library/itertools.html#itertools.count) | start, \[step\] | start, start+step, start+2\*step, ... | `count(10) --> 10 11 12 13 14 ...` |22| [`cycle()`](https://python-all.ru/3.4/library/itertools.html#itertools.cycle) | p | p0, p1, ... plast, p0, p1, ... | `cycle('ABCD') --> A B C D A B C D ...` |23| [`repeat()`](https://python-all.ru/3.4/library/itertools.html#itertools.repeat) | elem \[,n\] | elem, elem, elem, ... бесконечно или до n раз | `repeat(10, 3) --> 10 10 10` |2425**Итераторы, завершающиеся по кратчайшей входной последовательности:**2627| Итератор | Аргументы | Результаты | Пример |28| --- | --- | --- | --- |29| [`accumulate()`](https://python-all.ru/3.4/library/itertools.html#itertools.accumulate) | p \[,func\] | p0, p0+p1, p0+p1+p2, ... | `accumulate([1,2,3,4,5]) --> 1 3 6 10 15` |30| [`chain()`](https://python-all.ru/3.4/library/itertools.html#itertools.chain) | p, q, ... | p0, p1, ... plast, q0, q1, ... | `chain('ABC', 'DEF') --> A B C D E F` |31| [`chain.from_iterable()`](https://python-all.ru/3.4/library/itertools.html#itertools.chain.from_iterable) | итерируемый объект | p0, p1, ... plast, q0, q1, ... | `chain.from_iterable(['ABC', 'DEF']) --> A B C D E F` |32| [`compress()`](https://python-all.ru/3.4/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` |33| [`dropwhile()`](https://python-all.ru/3.4/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` |34| [`filterfalse()`](https://python-all.ru/3.4/library/itertools.html#itertools.filterfalse) | pred, seq | элементы seq, для которых pred(elem) ложно | `filterfalse(lambda x: x%2, range(10)) --> 0 2 4 6 8` |35| [`groupby()`](https://python-all.ru/3.4/library/itertools.html#itertools.groupby) | iterable\[, keyfunc\] | под-итераторы, сгруппированные по значению keyfunc(v) | |36| [`islice()`](https://python-all.ru/3.4/library/itertools.html#itertools.islice) | seq, \[start,\] stop \[, step\] | элементы из seq\[start:stop:step\] | `islice('ABCDEFG', 2, None) --> C D E F G` |37| [`starmap()`](https://python-all.ru/3.4/library/itertools.html#itertools.starmap) | func, seq | func(\*seq\[0\]), func(\*seq\[1\]), ... | `starmap(pow, [(2,5), (3,2), (10,3)]) --> 32 9 1000` |38| [`takewhile()`](https://python-all.ru/3.4/library/itertools.html#itertools.takewhile) | pred, seq | seq\[0\], seq\[1\], пока pred не вернёт ложь | `takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4` |39| [`tee()`](https://python-all.ru/3.4/library/itertools.html#itertools.tee) | it, n | it1, it2, ... itn разделяет один итератор на n | |40| [`zip_longest()`](https://python-all.ru/3.4/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-` |4142**Комбинаторные генераторы:**4344| Итератор | Аргументы | Результаты |45| --- | --- | --- |46| [`product()`](https://python-all.ru/3.4/library/itertools.html#itertools.product) | p, q, ... \[repeat=1\] | декартово произведение, эквивалентно вложенному циклу for |47| [`permutations()`](https://python-all.ru/3.4/library/itertools.html#itertools.permutations) | p\[, r\] | кортежи длиной r, все возможные перестановки, без повторяющихся элементов |48| [`combinations()`](https://python-all.ru/3.4/library/itertools.html#itertools.combinations) | p, r | кортежи длиной r, в отсортированном порядке, без повторяющихся элементов |49| [`combinations_with_replacement()`](https://python-all.ru/3.4/library/itertools.html#itertools.combinations_with_replacement) | p, r | кортежи длиной r, в отсортированном порядке, с повторяющимися элементами |50| `product('ABCD', repeat=2)` | | `AA AB AC AD BA BB BC BD CA CB CC CD DA DB DC DD` |51| `permutations('ABCD', 2)` | | `AB AC AD BA BC BD CA CB CD DA DB DC` |52| `combinations('ABCD', 2)` | | `AB AC AD BC BD CD` |53| `combinations_with_replacement('ABCD', 2)` | | `AA AB AC AD BB BC BD CC CD DD` |5455## 10.1.1. Функции itertool5657Следующие функции модуля создают и возвращают итераторы. Некоторые из них порождают потоки бесконечной длины, поэтому обращаться к ним следует только с помощью функций или циклов, которые обрывают поток.5859#### `itertools.accumulate(iterable[, func])`6061Создаёт итератор, возвращающий накопленные суммы. Элементами могут быть любые складываемые типы, включая [`Decimal`](https://python-all.ru/3.4/library/decimal.html#decimal.Decimal) или [`Fraction`](https://python-all.ru/3.4/library/fractions.html#fractions.Fraction). Если передан необязательный аргумент *func*, он должен быть функцией двух аргументов; она будет использоваться вместо сложения.6263Эквивалентно следующему:6465```python66def accumulate(iterable, func=operator.add):67 'Return running totals'68 # accumulate([1,2,3,4,5]) --> 1 3 6 10 1569 # accumulate([1,2,3,4,5], operator.mul) --> 1 2 6 24 12070 it = iter(iterable)71 total = next(it)72 yield total73 for element in it:74 total = func(total, element)75 yield total76```7778Аргумент *func* имеет множество применений. Его можно установить в [`min()`](https://python-all.ru/3.4/library/functions.html#min) для скользящего минимума, [`max()`](https://python-all.ru/3.4/library/functions.html#max) для скользящего максимума или [`operator.mul()`](https://python-all.ru/3.4/library/operator.html#operator.mul) для скользящего произведения. Таблицы амортизации можно построить, накапливая проценты и применяя платежи. Рекуррентные соотношения первого порядка [рекуррентные соотношения](https://python-all.ru/3.4/library/itertools.html) можно моделировать, передав начальное значение в итераторе и используя только накопленную сумму в аргументе *func*:7980```python81>>> data = [3, 4, 6, 2, 1, 9, 0, 7, 5, 8]82>>> list(accumulate(data, operator.mul)) # текущее произведение83[3, 12, 72, 144, 144, 1296, 0, 0, 0, 0]84>>> list(accumulate(data, max)) # текущий максимум85[3, 4, 6, 6, 6, 9, 9, 9, 9, 9]8687# Amortize a 5% loan of 1000 with 4 annual payments of 9088>>> cashflows = [1000, -90, -90, -90, -90]89>>> list(accumulate(cashflows, lambda bal, pmt: bal*1.05 + pmt))90[1000, 960.0, 918.0, 873.9000000000001, 827.5950000000001]9192# Chaotic recurrence relation http://en.wikipedia.org/wiki/Logistic_map93>>> logistic_map = lambda x, _: r * x * (1 - x)94>>> r = 3.895>>> x0 = 0.496>>> inputs = repeat(x0, 36) # используется только начальное значение97>>> [format(x, '.2f') for x in accumulate(inputs, logistic_map)]98['0.40', '0.91', '0.30', '0.81', '0.60', '0.92', '0.29', '0.79', '0.63',99 '0.88', '0.39', '0.90', '0.33', '0.84', '0.52', '0.95', '0.18', '0.57',100 '0.93', '0.25', '0.71', '0.79', '0.63', '0.88', '0.39', '0.91', '0.32',101 '0.83', '0.54', '0.95', '0.20', '0.60', '0.91', '0.30', '0.80', '0.60']102```103104См. [`functools.reduce()`](https://python-all.ru/3.4/library/functools.html#functools.reduce) – похожая функция, возвращающая только итоговое накопленное значение.105106Новое в версии 3.2.107108Изменено в версии 3.3: Добавлен необязательный параметр *func*.109110#### `itertools.chain(*iterables)`111112Создаёт итератор, возвращающий элементы из первого итерируемого объекта до его исчерпания, затем переходит к следующему и так далее, пока все итерируемые объекты не будут исчерпаны. Используется для обработки последовательных последовательностей как одной последовательности. Эквивалентно:113114```python115def chain(*iterables):116 # chain('ABC', 'DEF') --> A B C D E F117 for it in iterables:118 for element in it:119 yield element120```121122#### `classmethod chain.from_iterable(iterable)`123124Альтернативный конструктор для [`chain()`](https://python-all.ru/3.4/library/itertools.html#itertools.chain). Получает входные данные для цепочки из одного итерируемого аргумента, который вычисляется лениво. Примерно эквивалентно:125126```python127def from_iterable(iterables):128 # chain.from_iterable(['ABC', 'DEF']) --> A B C D E F129 for it in iterables:130 for element in it:131 yield element132```133134#### `itertools.combinations(iterable, r)`135136Возвращает подпоследовательности элементов длины *r* из входного *iterable*.137138Комбинации выдаются в лексикографическом порядке. Таким образом, если входной *итерируемый объект* отсортирован, кортежи комбинаций будут созданы в отсортированном порядке.139140Элементы считаются уникальными на основе их позиции, а не значения. Поэтому если входные элементы уникальны, то в каждой комбинации не будет повторяющихся значений.141142Эквивалентно следующему:143144```python145def combinations(iterable, r):146 # combinations('ABCD', 2) --> AB AC AD BC BD CD147 # combinations(range(4), 3) --> 012 013 023 123148 pool = tuple(iterable)149 n = len(pool)150 if r > n:151 return152 indices = list(range(r))153 yield tuple(pool[i] for i in indices)154 while True:155 for i in reversed(range(r)):156 if indices[i] != i + n - r:157 break158 else:159 return160 indices[i] += 1161 for j in range(i+1, r):162 indices[j] = indices[j-1] + 1163 yield tuple(pool[i] for i in indices)164```165166Код для [`combinations()`](https://python-all.ru/3.4/library/itertools.html#itertools.combinations) также можно выразить как подпоследовательность [`permutations()`](https://python-all.ru/3.4/library/itertools.html#itertools.permutations) после фильтрации записей, в которых элементы не отсортированы (согласно их позиции во входном пуле):167168```python169def combinations(iterable, r):170 pool = tuple(iterable)171 n = len(pool)172 for indices in permutations(range(n), r):173 if sorted(indices) == list(indices):174 yield tuple(pool[i] for i in indices)175```176177Количество возвращаемых элементов равно `n! / r! / (n-r)!`, когда `0 <= r <= n`, или нулю, когда `r > n`.178179#### `itertools.combinations_with_replacement(iterable, r)`180181Возвращает подпоследовательности элементов длины *r* из входного *iterable*, допуская повторение отдельных элементов.182183Комбинации выдаются в лексикографическом порядке. Таким образом, если входной *итерируемый объект* отсортирован, кортежи комбинаций будут созданы в отсортированном порядке.184185Элементы считаются уникальными по их позиции, а не по значению. Поэтому если входные элементы уникальны, сгенерированные комбинации также будут уникальны.186187Эквивалентно следующему:188189```python190def combinations_with_replacement(iterable, r):191 # combinations_with_replacement('ABC', 2) --> AA AB AC BB BC CC192 pool = tuple(iterable)193 n = len(pool)194 if not n and r:195 return196 indices = [0] * r197 yield tuple(pool[i] for i in indices)198 while True:199 for i in reversed(range(r)):200 if indices[i] != n - 1:201 break202 else:203 return204 indices[i:] = [indices[i] + 1] * (r - i)205 yield tuple(pool[i] for i in indices)206```207208Код для [`combinations_with_replacement()`](https://python-all.ru/3.4/library/itertools.html#itertools.combinations_with_replacement) также можно выразить как подпоследовательность [`product()`](https://python-all.ru/3.4/library/itertools.html#itertools.product) после фильтрации записей, в которых элементы не отсортированы (согласно их позиции во входном пуле):209210```python211def combinations_with_replacement(iterable, r):212 pool = tuple(iterable)213 n = len(pool)214 for indices in product(range(n), repeat=r):215 if sorted(indices) == list(indices):216 yield tuple(pool[i] for i in indices)217```218219Количество возвращаемых элементов равно `(n+r-1)! / r! / (n-1)!`, когда `n > 0`.220221Новое в версии 3.1.222223#### `itertools.compress(data, selectors)`224225Создаёт итератор, который фильтрует элементы из *data*, возвращая только те, для которых соответствующий элемент в *selectors* вычисляется как `True`. Останавливается, когда исчерпан либо *data*, либо *selectors*. Эквивалентно:226227```python228def compress(data, selectors):229 # compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F230 return (d for d, s in zip(data, selectors) if s)231```232233Новое в версии 3.1.234235#### `itertools.count(start=0, step=1)`236237Создаёт итератор, возвращающий равномерно распределённые значения, начиная с числа *start*. Часто используется как аргумент для [`map()`](https://python-all.ru/3.4/library/functions.html#map) для генерации последовательных точек данных. Также используется с [`zip()`](https://python-all.ru/3.4/library/functions.html#zip) для добавления порядковых номеров. Эквивалентно:238239```python240def count(start=0, step=1):241 # count(10) --> 10 11 12 13 14 ...242 # count(2.5, 0.5) -> 2.5 3.0 3.5 ...243 n = start244 while True:245 yield n246 n += step247```248249При подсчёте с числами с плавающей запятой иногда можно добиться лучшей точности, заменив его на мультипликативный код, например: `(start + step * i for i in count())`.250251Изменено в версии 3.1: Добавлен аргумент *step* и разрешены нецелые аргументы.252253#### `itertools.cycle(iterable)`254255Создаёт итератор, возвращающий элементы из итерируемого объекта и сохраняющий копию каждого. Когда итерируемый объект исчерпан, возвращает элементы из сохранённой копии. Повторяется бесконечно. Эквивалентно:256257```python258def cycle(iterable):259 # cycle('ABCD') --> A B C D A B C D A B C D ...260 saved = []261 for element in iterable:262 yield element263 saved.append(element)264 while saved:265 for element in saved:266 yield element267```268269Примечание: этот элемент набора инструментов может потребовать значительного дополнительного хранилища (в зависимости от длины итерабельного объекта).270271#### `itertools.dropwhile(predicate, iterable)`272273Создаёт итератор, который отбрасывает элементы из итерируемого объекта, пока предикат истинен; после этого возвращает каждый элемент. Обратите внимание: итератор не выдаёт *никакого* вывода, пока предикат не станет ложным, поэтому время запуска может быть значительным. Эквивалентно:274275```python276def dropwhile(predicate, iterable):277 # dropwhile(lambda x: x<5, [1,4,6,4,1]) --> 6 4 1278 iterable = iter(iterable)279 for x in iterable:280 if not predicate(x):281 yield x282 break283 for x in iterable:284 yield x285```286287#### `itertools.filterfalse(predicate, iterable)`288289Создаёт итератор, который фильтрует элементы из итерируемого объекта, возвращая только те, для которых предикат равен `False`. Если *predicate* равен `None`, возвращает элементы, которые являются ложными. Эквивалентно.290291```python292def filterfalse(predicate, iterable):293 # filterfalse(lambda x: x%2, range(10)) --> 0 2 4 6 8294 if predicate is None:295 predicate = bool296 for x in iterable:297 if not predicate(x):298 yield x299```300301#### `itertools.groupby(iterable, key=None)`302303Создаёт итератор, который возвращает последовательные ключи и группы из *iterable*. *key* – это функция, вычисляющая ключевое значение для каждого элемента. Если он не указан или равен `None`, то *key* по умолчанию принимает тождественную функцию и возвращает элемент без изменений. Обычно iterable должен быть отсортирован по той же ключевой функции.304305Работа [`groupby()`](https://python-all.ru/3.4/library/itertools.html#itertools.groupby) похожа на фильтр `uniq` в Unix. Она создаёт разрыв или новую группу каждый раз, когда значение ключевой функции меняется (именно поэтому данные обычно необходимо отсортировать с помощью той же ключевой функции). Такое поведение отличается от SQL’s GROUP BY, которое объединяет общие элементы независимо от их порядка во входных данных.306307Возвращаемая группа сама является итератором, который использует тот же исходный итератор, что и [`groupby()`](https://python-all.ru/3.4/library/itertools.html#itertools.groupby). Поскольку источник общий, когда [`groupby()`](https://python-all.ru/3.4/library/itertools.html#itertools.groupby) объект продвигается, предыдущая группа перестаёт быть видимой. Поэтому, если эти данные потребуются позже, их следует сохранить в виде списка:308309```python310groups = []311uniquekeys = []312data = sorted(data, key=keyfunc)313for k, g in groupby(data, keyfunc):314 groups.append(list(g)) # Сохранить групповой итератор как список315 uniquekeys.append(k)316```317318[`groupby()`](https://python-all.ru/3.4/library/itertools.html#itertools.groupby) эквивалентен следующему:319320```python321class groupby:322 # [k for k, g in groupby('AAAABBBCCDAABBB')] --> A B C D A B323 # [list(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D324 def __init__(self, iterable, key=None):325 if key is None:326 key = lambda x: x327 self.keyfunc = key328 self.it = iter(iterable)329 self.tgtkey = self.currkey = self.currvalue = object()330 def __iter__(self):331 return self332 def __next__(self):333 while self.currkey == self.tgtkey:334 self.currvalue = next(self.it) # Выход при StopIteration335 self.currkey = self.keyfunc(self.currvalue)336 self.tgtkey = self.currkey337 return (self.currkey, self._grouper(self.tgtkey))338 def _grouper(self, tgtkey):339 while self.currkey == tgtkey:340 yield self.currvalue341 self.currvalue = next(self.it) # Выход при StopIteration342 self.currkey = self.keyfunc(self.currvalue)343```344345#### `itertools.islice(iterable, stop)`346347#### `itertools.islice(iterable, start, stop[, step])`348349Создаёт итератор, который возвращает выбранные элементы из iterable. Если *start* не равен нулю, то элементы из iterable пропускаются до тех пор, пока не будет достигнут start. После этого элементы возвращаются подряд, если только *step* не больше единицы, что приводит к пропуску элементов. Если *stop* равен `None`, то итерация продолжается, пока итератор не исчерпается; в противном случае она останавливается на указанной позиции. В отличие от обычного среза, [`islice()`](https://python-all.ru/3.4/library/itertools.html#itertools.islice) не поддерживает отрицательные значения для *start*, *stop* или *step*. Может использоваться для извлечения связанных полей из данных, у которых внутренняя структура была сплющена (например, в многострочном отчёте поле имени может располагаться на каждой третьей строке). Эквивалентен:350351```python352def islice(iterable, *args):353 # islice('ABCDEFG', 2) --> A B354 # islice('ABCDEFG', 2, 4) --> C D355 # islice('ABCDEFG', 2, None) --> C D E F G356 # islice('ABCDEFG', 0, None, 2) --> A C E G357 s = slice(*args)358 it = iter(range(s.start or 0, s.stop or sys.maxsize, s.step or 1))359 nexti = next(it)360 for i, element in enumerate(iterable):361 if i == nexti:362 yield element363 nexti = next(it)364```365366Если *start* равен `None`, то итерация начинается с нуля. Если *step* равен `None`, то шаг по умолчанию равен единице.367368#### `itertools.permutations(iterable, r=None)`369370Возвращает последовательные перестановки длины *r* элементов из *iterable*.371372Если *r* не указан или равен `None`, то *r* по умолчанию принимает длину *iterable* и генерируются все возможные перестановки полной длины.373374Перестановки выдаются в лексикографическом порядке. Таким образом, если входной *итерируемый объект* отсортирован, кортежи перестановок будут созданы в отсортированном порядке.375376Элементы считаются уникальными на основе их позиции, а не значения. Поэтому если входные элементы уникальны, то в каждой перестановке не будет повторяющихся значений.377378Эквивалентно следующему:379380```python381def permutations(iterable, r=None):382 # permutations('ABCD', 2) --> AB AC AD BA BC BD CA CB CD DA DB DC383 # permutations(range(3)) --> 012 021 102 120 201 210384 pool = tuple(iterable)385 n = len(pool)386 r = n if r is None else r387 if r > n:388 return389 indices = list(range(n))390 cycles = list(range(n, n-r, -1))391 yield tuple(pool[i] for i in indices[:r])392 while n:393 for i in reversed(range(r)):394 cycles[i] -= 1395 if cycles[i] == 0:396 indices[i:] = indices[i+1:] + indices[i:i+1]397 cycles[i] = n - i398 else:399 j = cycles[i]400 indices[i], indices[-j] = indices[-j], indices[i]401 yield tuple(pool[i] for i in indices[:r])402 break403 else:404 return405```406407Код для [`permutations()`](https://python-all.ru/3.4/library/itertools.html#itertools.permutations) можно также выразить как подпоследовательность [`product()`](https://python-all.ru/3.4/library/itertools.html#itertools.product), отфильтрованную для исключения записей с повторяющимися элементами (тех, что находятся на одной и той же позиции во входном пуле):408409```python410def permutations(iterable, r=None):411 pool = tuple(iterable)412 n = len(pool)413 r = n if r is None else r414 for indices in product(range(n), repeat=r):415 if len(set(indices)) == r:416 yield tuple(pool[i] for i in indices)417```418419Количество возвращаемых элементов равно `n! / (n-r)!`, когда `0 <= r <= n` или нулю, когда `r > n`.420421#### `itertools.product(*iterables, repeat=1)`422423Декартово произведение входных итерируемых объектов.424425Эквивалентно вложенным циклам for в генераторном выражении. Например, `product(A, B)` возвращает то же, что и `((x,y) for x in A for y in B)`.426427Вложенные циклы работают как одометр: самый правый элемент увеличивается на каждой итерации. Этот шаблон создает лексикографический порядок, так что если входные итерируемые объекты отсортированы, кортежи произведения выдаются в отсортированном порядке.428429Чтобы вычислить произведение итератора самого на себя, укажите количество повторений с помощью необязательного именованного аргумента *repeat*. Например, `product(A, repeat=4)` означает то же, что и `product(A, A, A, A)`.430431Эта функция эквивалентна следующему коду, за исключением того, что реальная реализация не создаёт промежуточные результаты в памяти:432433```python434def product(*args, repeat=1):435 # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy436 # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111437 pools = [tuple(pool) for pool in args] * repeat438 result = [[]]439 for pool in pools:440 result = [x+[y] for x in result for y in pool]441 for prod in result:442 yield tuple(prod)443```444445#### `itertools.repeat(object[, times])`446447Создаёт итератор, который снова и снова возвращает *object*. Работает бесконечно, если не указан аргумент *times*. Используется как аргумент для [`map()`](https://python-all.ru/3.4/library/functions.html#map) для неизменяемых параметров вызываемой функции. Также используется с [`zip()`](https://python-all.ru/3.4/library/functions.html#zip) для создания неизменяемой части записи кортежа. Эквивалентен:448449```python450def repeat(object, times=None):451 # repeat(10, 3) --> 10 10 10452 if times is None:453 while True:454 yield object455 else:456 for i in range(times):457 yield object458```459460Обычное применение *repeat* – передача потока постоянных значений в *map* или *zip*:461462```python463>>> list(map(pow, range(10), repeat(2)))464[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]465```466467#### `itertools.starmap(function, iterable)`468469Создаёт итератор, который вычисляет функцию, используя аргументы, полученные из итератора. Используется вместо [`map()`](https://python-all.ru/3.4/library/functions.html#map), когда аргументы уже сгруппированы в кортежи из одного итератора (данные были «предварительно сжаты»). Разница между [`map()`](https://python-all.ru/3.4/library/functions.html#map) и [`starmap()`](https://python-all.ru/3.4/library/itertools.html#itertools.starmap) аналогична различию между `function(a,b)` и `function(*c)`. Эквивалентен:470471```python472def starmap(function, iterable):473 # starmap(pow, [(2,5), (3,2), (10,3)]) --> 32 9 1000474 for args in iterable:475 yield function(*args)476```477478#### `itertools.takewhile(predicate, iterable)`479480Создаёт итератор, который возвращает элементы из итератора, пока предикат истинен. Эквивалентен:481482```python483def takewhile(predicate, iterable):484 # takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4485 for x in iterable:486 if predicate(x):487 yield x488 else:489 break490```491492#### `itertools.tee(iterable, n=2)`493494Возвращает *n* независимых итераторов из одного итератора. Эквивалентен:495496```python497def tee(iterable, n=2):498 it = iter(iterable)499 deques = [collections.deque() for i in range(n)]500 def gen(mydeque):501 while True:502 if not mydeque: # когда локальная deque пуста503 newval = next(it) # извлечь новое значение и504 for d in deques: # загрузить его во все двусторонние очереди505 d.append(newval)506 yield mydeque.popleft()507 return tuple(gen(d) for d in deques)508```509510После того, как [`tee()`](https://python-all.ru/3.4/library/itertools.html#itertools.tee) произвел разделение, исходный *iterable* не должен использоваться где-либо ещё; в противном случае *iterable* может быть продвинут без уведомления объектов tee.511512Этот инструмент итерации может потребовать значительного объёма дополнительной памяти (в зависимости от того, сколько временных данных нужно сохранить). В общем случае, если один итератор использует большую часть или все данные до того, как запускается другой итератор, быстрее использовать [`list()`](https://python-all.ru/3.4/library/stdtypes.html#list) вместо [`tee()`](https://python-all.ru/3.4/library/itertools.html#itertools.tee).513514#### `itertools.zip_longest(*iterables, fillvalue=None)`515516Создаёт итератор, который объединяет элементы из каждого из итераторов. Если итераторы имеют разную длину, отсутствующие значения заполняются с помощью *fillvalue*. Итерация продолжается, пока самый длинный итератор не будет исчерпан. Эквивалентен:517518```python519class ZipExhausted(Exception):520 pass521522def zip_longest(*args, **kwds):523 # zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-524 fillvalue = kwds.get('fillvalue')525 counter = len(args) - 1526 def sentinel():527 nonlocal counter528 if not counter:529 raise ZipExhausted530 counter -= 1531 yield fillvalue532 fillers = repeat(fillvalue)533 iterators = [chain(it, sentinel(), fillers) for it in args]534 try:535 while iterators:536 yield tuple(map(next, iterators))537 except ZipExhausted:538 pass539```540541Если один из итераторов потенциально бесконечен, то функция [`zip_longest()`](https://python-all.ru/3.4/library/itertools.html#itertools.zip_longest) должна быть обёрнута чем-то, что ограничивает количество вызовов (например, [`islice()`](https://python-all.ru/3.4/library/itertools.html#itertools.islice) или [`takewhile()`](https://python-all.ru/3.4/library/itertools.html#itertools.takewhile)). Если не указано, *fillvalue* по умолчанию равен `None`.542543## 10.1.2. Рецепты itertools544545В этом разделе представлены рецепты для создания расширенного набора инструментов с использованием существующих itertools в качестве строительных блоков.546547Расширенные инструменты обеспечивают такую же высокую производительность, как и базовый набор инструментов. Превосходная производительность по памяти достигается за счёт обработки элементов по одному, а не загрузки всего итерируемого объекта в память сразу. Объём кода остаётся небольшим благодаря связыванию инструментов в функциональном стиле, что помогает избавиться от временных переменных. Высокая скорость сохраняется за счёт предпочтения «векторизованных» строительных блоков вместо использования циклов for и [*генераторов*](https://python-all.ru/3.4/glossary.html#term-generator), которые создают накладные расходы интерпретатора.548549```python550def take(n, iterable):551 "Return first n items of the iterable as a list"552 return list(islice(iterable, n))553554def tabulate(function, start=0):555 "Return function(0), function(1), ..."556 return map(function, count(start))557558def consume(iterator, n):559 "Advance the iterator n-steps ahead. If n is none, consume entirely."560 # Используйте функции, потребляющие итераторы на скорости C.561 if n is None:562 # передать весь итератор в deque нулевой длины563 collections.deque(iterator, maxlen=0)564 else:565 # перейти к пустому срезу начиная с позиции n566 next(islice(iterator, n, n), None)567568def nth(iterable, n, default=None):569 "Returns the nth item or a default value"570 return next(islice(iterable, n, None), default)571572def quantify(iterable, pred=bool):573 "Count how many times the predicate is true"574 return sum(map(pred, iterable))575576def padnone(iterable):577 """Возвращает элементы последовательности, а затем бесконечно возвращает None.578579 Полезно для эмуляции поведения встроенной функции map().580 """581 return chain(iterable, repeat(None))582583def ncycles(iterable, n):584 "Returns the sequence elements n times"585 return chain.from_iterable(repeat(tuple(iterable), n))586587def dotproduct(vec1, vec2):588 return sum(map(operator.mul, vec1, vec2))589590def flatten(listOfLists):591 "Flatten one level of nesting"592 return chain.from_iterable(listOfLists)593594def repeatfunc(func, times=None, *args):595 """Повторяет вызовы func с указанными аргументами.596597 Пример: repeatfunc(random.random)598 """599 if times is None:600 return starmap(func, repeat(args))601 return starmap(func, repeat(args, times))602603def pairwise(iterable):604 "s -> (s0,s1), (s1,s2), (s2, s3), ..."605 a, b = tee(iterable)606 next(b, None)607 return zip(a, b)608609def grouper(iterable, n, fillvalue=None):610 "Collect data into fixed-length chunks or blocks"611 # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"612 args = [iter(iterable)] * n613 return zip_longest(*args, fillvalue=fillvalue)614615def roundrobin(*iterables):616 "roundrobin('ABC', 'D', 'EF') --> A D E B F C"617 # Автор рецепта – Джордж Саккис618 pending = len(iterables)619 nexts = cycle(iter(it).__next__ for it in iterables)620 while pending:621 try:622 for next in nexts:623 yield next()624 except StopIteration:625 pending -= 1626 nexts = cycle(islice(nexts, pending))627628def partition(pred, iterable):629 'Use a predicate to partition entries into false entries and true entries'630 # partition(is_odd, range(10)) --> 0 2 4 6 8 и 1 3 5 7 9631 t1, t2 = tee(iterable)632 return filterfalse(pred, t1), filter(pred, t2)633634def powerset(iterable):635 "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"636 s = list(iterable)637 return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))638639def unique_everseen(iterable, key=None):640 "List unique elements, preserving order. Remember all elements ever seen."641 # unique_everseen('AAAABBBCCDAABBB') --> A B C D642 # unique_everseen('ABBCcAD', str.lower) --> A B C D643 seen = set()644 seen_add = seen.add645 if key is None:646 for element in filterfalse(seen.__contains__, iterable):647 seen_add(element)648 yield element649 else:650 for element in iterable:651 k = key(element)652 if k not in seen:653 seen_add(k)654 yield element655656def unique_justseen(iterable, key=None):657 "List unique elements, preserving order. Remember only the element just seen."658 # unique_justseen('AAAABBBCCDAABBB') --> A B C D A B659 # unique_justseen('ABBCcAD', str.lower) --> A B C A D660 return map(next, map(itemgetter(1), groupby(iterable, key)))661662def iter_except(func, exception, first=None):663 """ Повторно вызывает функцию до возникновения исключения.664665 Преобразует интерфейс вызова до исключения в интерфейс итератора.666 Как builtins.iter(func, sentinel), но использует исключение вместо667 сигнального значения для завершения цикла.668669 Примеры:670 iter_except(functools.partial(heappop, h), IndexError) # итератор очереди с приоритетом671 iter_except(d.popitem, KeyError) # итератор словаря без блокировки672 iter_except(d.popleft, IndexError) # итератор дека без блокировки673 iter_except(q.get_nowait, Queue.Empty) # цикл по очереди производителя674 iter_except(s.pop, KeyError) # итератор множества без блокировки675676 """677 try:678 if first is not None:679 yield first() # Для API баз данных, требующих первоначального приведения к db.first()680 while 1:681 yield func()682 except exception:683 pass684685def first_true(iterable, default=False, pred=None):686 """Возвращает первое истинное значение в итерируемом объекте.687688 Если истинное значение не найдено, возвращает *default*689690 Если *pred* не равен None, возвращает первый элемент691 для которого pred(item) истинно.692693 """694 # first_true([a,b,c], x) --> a или b или c или x695 # first_true([a,b], x, f) --> a если f(a) иначе b если f(b) иначе x696 return next(filter(pred, iterable), default)697698def random_product(*args, repeat=1):699 "Random selection from itertools.product(*args, **kwds)"700 pools = [tuple(pool) for pool in args] * repeat701 return tuple(random.choice(pool) for pool in pools)702703def random_permutation(iterable, r=None):704 "Random selection from itertools.permutations(iterable, r)"705 pool = tuple(iterable)706 r = len(pool) if r is None else r707 return tuple(random.sample(pool, r))708709def random_combination(iterable, r):710 "Random selection from itertools.combinations(iterable, r)"711 pool = tuple(iterable)712 n = len(pool)713 indices = sorted(random.sample(range(n), r))714 return tuple(pool[i] for i in indices)715716def random_combination_with_replacement(iterable, r):717 "Random selection from itertools.combinations_with_replacement(iterable, r)"718 pool = tuple(iterable)719 n = len(pool)720 indices = sorted(random.randrange(n) for i in range(r))721 return tuple(pool[i] for i in indices)722```723724Обратите внимание: многие из приведённых выше рецептов можно оптимизировать, заменив глобальные поиски локальными переменными, определёнными как значения по умолчанию. Например, рецепт *dotproduct* можно записать так:725726```python727def dotproduct(vec1, vec2, sum=sum, map=map, mul=operator.mul):728 return sum(map(mul, vec1, vec2))729```730