itertools.md
1> **Источник:** https://python-all.ru/3.13/library/itertools.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# `itertools` – Функции, создающие итераторы для эффективного перебора89---1011Этот модуль реализует ряд строительных блоков [итераторов](https://python-all.ru/3.13/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.13/library/functions.html#map) и [`count()`](https://python-all.ru/3.13/library/itertools.html#itertools.count) для получения `map(f, count())`.1617**Бесконечные итераторы:**1819| Итератор | Аргументы | Результаты | Пример |20| --- | --- | --- | --- |21| [`count()`](https://python-all.ru/3.13/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.13/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.13/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.13/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| [`batched()`](https://python-all.ru/3.13/library/itertools.html#itertools.batched) | p, n | (p0, p1, …, p\_n-1), … | `batched('ABCDEFG', n=3) → ABC DEF G` |31| [`chain()`](https://python-all.ru/3.13/library/itertools.html#itertools.chain) | p, q, … | p0, p1, … plast, q0, q1, … | `chain('ABC', 'DEF') → A B C D E F` |32| [`chain.from_iterable()`](https://python-all.ru/3.13/library/itertools.html#itertools.chain.from_iterable) | iterable | p0, p1, … plast, q0, q1, … | `chain.from_iterable(['ABC', 'DEF']) → A B C D E F` |33| [`compress()`](https://python-all.ru/3.13/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` |34| [`dropwhile()`](https://python-all.ru/3.13/library/itertools.html#itertools.dropwhile) | predicate, seq | seq\[n\], seq\[n+1\], начиная с момента, когда предикат не выполняется | `dropwhile(lambda x: x<5, [1,4,6,3,8]) → 6 3 8` |35| [`filterfalse()`](https://python-all.ru/3.13/library/itertools.html#itertools.filterfalse) | predicate, seq | элементы seq, для которых predicate(elem) не выполняется | `filterfalse(lambda x: x<5, [1,4,6,3,8]) → 6 8` |36| [`groupby()`](https://python-all.ru/3.13/library/itertools.html#itertools.groupby) | iterable\[, key\] | подитераторы, сгруппированные по значению key(v) | `groupby(['A','B','DEF'], len) → (1, A B) (3, DEF)` |37| [`islice()`](https://python-all.ru/3.13/library/itertools.html#itertools.islice) | seq, \[start,\] stop \[, step\] | элементы из seq\[start:stop:step\] | `islice('ABCDEFG', 2, None) → C D E F G` |38| [`pairwise()`](https://python-all.ru/3.13/library/itertools.html#itertools.pairwise) | iterable | (p\[0\], p\[1\]), (p\[1\], p\[2\]) | `pairwise('ABCDEFG') → AB BC CD DE EF FG` |39| [`starmap()`](https://python-all.ru/3.13/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.13/library/itertools.html#itertools.takewhile) | predicate, seq | seq\[0\], seq\[1\], пока predicate не вернёт ложь | `takewhile(lambda x: x<5, [1,4,6,3,8]) → 1 4` |41| [`tee()`](https://python-all.ru/3.13/library/itertools.html#itertools.tee) | it, n | it1, it2, … itn разделяет один итератор на n | |42| [`zip_longest()`](https://python-all.ru/3.13/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.13/library/itertools.html#itertools.product) | p, q, … \[repeat=1\] | декартово произведение, эквивалентно вложенному циклу for |49| [`permutations()`](https://python-all.ru/3.13/library/itertools.html#itertools.permutations) | p\[, r\] | кортежи длиной r, все возможные перестановки, без повторяющихся элементов |50| [`combinations()`](https://python-all.ru/3.13/library/itertools.html#itertools.combinations) | p, r | кортежи длиной r, в отсортированном порядке, без повторяющихся элементов |51| [`combinations_with_replacement()`](https://python-all.ru/3.13/library/itertools.html#itertools.combinations_with_replacement) | p, r | кортежи длиной r, в отсортированном порядке, с повторяющимися элементами |5253| Примеры | Результаты |54| --- | --- |55| `product('ABCD', repeat=2)` | `AA AB AC AD BA BB BC BD CA CB CC CD DA DB DC DD` |56| `permutations('ABCD', 2)` | `AB AC AD BA BC BD CA CB CD DA DB DC` |57| `combinations('ABCD', 2)` | `AB AC AD BC BD CD` |58| `combinations_with_replacement('ABCD', 2)` | `AA AB AC AD BB BC BD CC CD DD` |5960## Функции itertools6162Следующие функции создают и возвращают итераторы. Некоторые из них дают потоки бесконечной длины, поэтому их следует использовать только в функциях или циклах, которые обрезают поток.6364#### `itertools.accumulate(iterable[, function, *, initial=None])`6566Создаёт итератор, возвращающий накопленные суммы или накопленные результаты других бинарных функций.6768Если *function* не указана, по умолчанию используется сложение. *Function* должна принимать два аргумента: накопленное значение и очередной элемент из *iterable*.6970Если указано начальное значение *initial*, накопление начнётся с него, и в результате будет на один элемент больше, чем во входном итерируемом объекте.7172Примерно эквивалентно:7374```python75def accumulate(iterable, function=operator.add, *, initial=None):76 'Return running totals'77 # accumulate([1,2,3,4,5]) → 1 3 6 10 1578 # accumulate([1,2,3,4,5], initial=100) → 100 101 103 106 110 11579 # accumulate([1,2,3,4,5], operator.mul) → 1 2 6 24 1208081 iterator = iter(iterable)82 total = initial83 if initial is None:84 try:85 total = next(iterator)86 except StopIteration:87 return8889 yield total90 for element in iterator:91 total = function(total, element)92 yield total93```9495Чтобы вычислить текущий минимум, задайте *function* равной [`min()`](https://python-all.ru/3.13/library/functions.html#min). Для текущего максимума – *function* [`max()`](https://python-all.ru/3.13/library/functions.html#max). Для текущего произведения – *function* [`operator.mul()`](https://python-all.ru/3.13/library/operator.html#operator.mul). Для построения [таблицы амортизации](https://python-all.ru/3.13/library/itertools.html) накопите проценты и примените платежи:9697```pycon98>>> data = [3, 4, 6, 2, 1, 9, 0, 7, 5, 8]99>>> list(accumulate(data, max)) # текущий максимум100[3, 4, 6, 6, 6, 9, 9, 9, 9, 9]101>>> list(accumulate(data, operator.mul)) # текущее произведение102[3, 12, 72, 144, 144, 1296, 0, 0, 0, 0]103104# Amortize a 5% loan of 1000 with 10 annual payments of 90105>>> update = lambda balance, payment: round(balance * 1.05) - payment106>>> list(accumulate(repeat(90, 10), update, initial=1_000))107[1000, 960, 918, 874, 828, 779, 728, 674, 618, 559, 497]108```109110См. [`functools.reduce()`](https://python-all.ru/3.13/library/functools.html#functools.reduce) – похожая функция, возвращающая только итоговое накопленное значение.111112Добавлено в версии 3.2.113114Изменено в версии 3.3: Добавлен необязательный параметр *function*.115116Изменено в версии 3.8: Добавлен необязательный параметр *initial*.117118#### `itertools.batched(iterable, n, *, strict=False)`119120Группирует данные из *iterable* в кортежи длины *n*. Последняя группа может быть короче *n*.121122Если *strict* равен True, будет вызвано исключение [`ValueError`](https://python-all.ru/3.13/library/exceptions.html#ValueError), если последняя группа короче *n*.123124Перебирает входной iterable и накапливает данные в кортежи размером до *n*. Входные данные обрабатываются лениво – ровно столько, чтобы заполнить одну группу. Результат возвращается сразу, как только группа заполнена или входной iterable исчерпан:125126```pycon127>>> flattened_data = ['roses', 'red', 'violets', 'blue', 'sugar', 'sweet']128>>> unflattened = list(batched(flattened_data, 2))129>>> unflattened130[('roses', 'red'), ('violets', 'blue'), ('sugar', 'sweet')]131```132133Примерно эквивалентно:134135```python136def batched(iterable, n, *, strict=False):137 # batched('ABCDEFG', 3) → ABC DEF G138 if n < 1:139 raise ValueError('n must be at least one')140 iterator = iter(iterable)141 while batch := tuple(islice(iterator, n)):142 if strict and len(batch) != n:143 raise ValueError('batched(): incomplete batch')144 yield batch145```146147Добавлено в версии 3.12.148149Изменено в версии 3.13: Добавлен параметр *strict*.150151#### `itertools.chain(*iterables)`152153Создаёт итератор, который возвращает элементы из первого iterable, пока он не исчерпан, затем переходит к следующему, и так до исчерпания всех. Это объединяет несколько источников данных в один итератор. Примерная реализация:154155```python156def chain(*iterables):157 # chain('ABC', 'DEF') → A B C D E F158 for iterable in iterables:159 yield from iterable160```161162#### `classmethod chain.from_iterable(iterable)`163164Альтернативный конструктор для [`chain()`](https://python-all.ru/3.13/library/itertools.html#itertools.chain). Получает цепочку входных данных из одного аргумента iterable, который вычисляется лениво. Примерная реализация:165166```python167def from_iterable(iterables):168 # chain.from_iterable(['ABC', 'DEF']) → A B C D E F169 for iterable in iterables:170 yield from iterable171```172173#### `itertools.combinations(iterable, r)`174175Возвращает подпоследовательности элементов длины *r* из входного *iterable*.176177Результат является подмножеством [`product()`](https://python-all.ru/3.13/library/itertools.html#itertools.product), в котором оставлены только те элементы, которые являются подпоследовательностями *iterable*. Длина результата задаётся выражением [`math.comb()`](https://python-all.ru/3.13/library/math.html#math.comb), которое равно `n! / r! / (n - r)!`, если `0 ≤ r ≤ n`, или нулю, если `r > n`.178179Кортежи-комбинации порождаются в лексикографическом порядке по порядку входного *iterable*. Если входной *iterable* отсортирован, выходные кортежи также будут отсортированы.180181Элементы считаются уникальными по позиции, а не по значению. Если входные элементы уникальны, то в каждой комбинации не будет повторяющихся значений.182183Примерно эквивалентно:184185```python186def combinations(iterable, r):187 # combinations('ABCD', 2) → AB AC AD BC BD CD188 # combinations(range(4), 3) → 012 013 023 123189190 pool = tuple(iterable)191 n = len(pool)192 if r > n:193 return194 indices = list(range(r))195196 yield tuple(pool[i] for i in indices)197 while True:198 for i in reversed(range(r)):199 if indices[i] != i + n - r:200 break201 else:202 return203 indices[i] += 1204 for j in range(i+1, r):205 indices[j] = indices[j-1] + 1206 yield tuple(pool[i] for i in indices)207```208209#### `itertools.combinations_with_replacement(iterable, r)`210211Возвращает подпоследовательности элементов длины *r* из входного *iterable*, допуская повторение отдельных элементов.212213Результат является подмножеством [`product()`](https://python-all.ru/3.13/library/itertools.html#itertools.product), в котором оставлены только те элементы, которые являются подпоследовательностями (с возможными повторениями) *iterable*. Количество возвращаемых подпоследовательностей равно `(n + r - 1)! / r! / (n - 1)!`, если `n > 0`.214215Кортежи-комбинации порождаются в лексикографическом порядке по порядку входного *iterable*. Если входной *iterable* отсортирован, выходные кортежи будут отсортированы.216217Элементы считаются уникальными по позиции, а не по значению. Если входные элементы уникальны, то порождённые комбинации тоже будут уникальны.218219Примерно эквивалентно:220221```python222def combinations_with_replacement(iterable, r):223 # combinations_with_replacement('ABC', 2) → AA AB AC BB BC CC224225 pool = tuple(iterable)226 n = len(pool)227 if not n and r:228 return229 indices = [0] * r230231 yield tuple(pool[i] for i in indices)232 while True:233 for i in reversed(range(r)):234 if indices[i] != n - 1:235 break236 else:237 return238 indices[i:] = [indices[i] + 1] * (r - i)239 yield tuple(pool[i] for i in indices)240```241242Добавлено в версии 3.1.243244#### `itertools.compress(data, selectors)`245246Создаёт итератор, который возвращает элементы из *data*, для которых соответствующий элемент из *selectors* истинен. Останавливается, когда исчерпан либо *data*, либо *selectors*. Примерная реализация:247248```python249def compress(data, selectors):250 # compress('ABCDEF', [1,0,1,0,1,1]) → A C E F251 return (datum for datum, selector in zip(data, selectors) if selector)252```253254Добавлено в версии 3.1.255256#### `itertools.count(start=0, step=1)`257258Создаёт итератор, возвращающий равномерно расположенные значения, начиная с *start*. Может использоваться с [`map()`](https://python-all.ru/3.13/library/functions.html#map) для генерации последовательных точек данных или с [`zip()`](https://python-all.ru/3.13/library/functions.html#zip) для добавления номеров по порядку. Примерная реализация:259260```python261def count(start=0, step=1):262 # count(10) → 10 11 12 13 14 ...263 # count(2.5, 0.5) → 2.5 3.0 3.5 ...264 n = start265 while True:266 yield n267 n += step268```269270При подсчёте с числами с плавающей точкой иногда лучшей точности можно добиться, используя мультипликативный код, например: `(start + step * i for i in count())`.271272Изменено в версии 3.1: Добавлен аргумент *step* и разрешены нецелые аргументы.273274#### `itertools.cycle(iterable)`275276Создаёт итератор, который возвращает элементы из *iterable* и сохраняет копию каждого. Когда iterable исчерпан, возвращает элементы из сохранённой копии. Повторяется бесконечно. Примерная реализация:277278```python279def cycle(iterable):280 # cycle('ABCD') → A B C D A B C D A B C D ...281282 saved = []283 for element in iterable:284 yield element285 saved.append(element)286287 while saved:288 for element in saved:289 yield element290```291292Этот инструмент может потребовать значительного объёма дополнительной памяти (в зависимости от длины iterable).293294#### `itertools.dropwhile(predicate, iterable)`295296Создаёт итератор, который пропускает элементы из *iterable*, пока *predicate* истинен, а затем возвращает все оставшиеся элементы. Примерная реализация:297298```python299def dropwhile(predicate, iterable):300 # dropwhile(lambda x: x<5, [1,4,6,3,8]) → 6 3 8301302 iterator = iter(iterable)303 for x in iterator:304 if not predicate(x):305 yield x306 break307308 for x in iterator:309 yield x310```311312Обратите внимание: этот итератор не выдаёт *ни одного* элемента, пока предикат впервые не станет ложным, поэтому время запуска может быть большим.313314#### `itertools.filterfalse(predicate, iterable)`315316Создаёт итератор, который фильтрует элементы из *iterable*, возвращая только те, для которых *predicate* возвращает ложное значение. Если *predicate* равен `None`, возвращает элементы, которые являются ложными. Примерная реализация:317318```python319def filterfalse(predicate, iterable):320 # filterfalse(lambda x: x<5, [1,4,6,3,8]) → 6 8321322 if predicate is None:323 predicate = bool324325 for x in iterable:326 if not predicate(x):327 yield x328```329330#### `itertools.groupby(iterable, key=None)`331332Make 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.333334Работа `groupby()` аналогична фильтру `uniq` в Unix. Она создает разрыв или новую группу каждый раз, когда изменяется значение ключевой функции (поэтому обычно необходимо отсортировать данные с помощью той же ключевой функции). Такое поведение отличается от SQL GROUP BY, которая объединяет общие элементы независимо от порядка их ввода.335336Возвращаемая группа сама является итератором, который использует общий исходный итерируемый объект с `groupby()`. Поскольку источник общий, при продвижении объекта `groupby()` предыдущая группа перестает быть видимой. Поэтому, если эти данные понадобятся позже, их следует сохранить в виде списка:337338```python339groups = []340uniquekeys = []341data = sorted(data, key=keyfunc)342for k, g in groupby(data, keyfunc):343 groups.append(list(g)) # Сохранить групповой итератор как список344 uniquekeys.append(k)345```346347`groupby()` примерно эквивалентно:348349```python350def groupby(iterable, key=None):351 # [k for k, g in groupby('AAAABBBCCDAABBB')] → A B C D A B352 # [list(g) for k, g in groupby('AAAABBBCCD')] → AAAA BBB CC D353354 keyfunc = (lambda x: x) if key is None else key355 iterator = iter(iterable)356 exhausted = False357358 def _grouper(target_key):359 nonlocal curr_value, curr_key, exhausted360 yield curr_value361 for curr_value in iterator:362 curr_key = keyfunc(curr_value)363 if curr_key != target_key:364 return365 yield curr_value366 exhausted = True367368 try:369 curr_value = next(iterator)370 except StopIteration:371 return372 curr_key = keyfunc(curr_value)373374 while not exhausted:375 target_key = curr_key376 curr_group = _grouper(target_key)377 yield curr_key, curr_group378 if curr_key == target_key:379 for _ in curr_group:380 pass381```382383#### `itertools.islice(iterable, stop)`384385#### `itertools.islice(iterable, start, stop[, step])`386387Создает итератор, который возвращает выбранные элементы из итерируемого объекта. Работает как срез последовательности, но не поддерживает отрицательные значения для *start*, *stop* или *step*.388389Если *start* равен нулю или `None`, итерация начинается с нуля. В противном случае элементы из итерируемого объекта пропускаются до достижения *start*.390391Если *stop* равен `None`, итерация продолжается до тех пор, пока входной объект не будет исчерпан. В противном случае она останавливается на указанной позиции.392393Если *step* равен `None`, шаг по умолчанию равен единице. Элементы возвращаются последовательно, если только *step* не больше единицы, что приводит к пропуску элементов.394395Примерно эквивалентно:396397```python398def islice(iterable, *args):399 # islice('ABCDEFG', 2) → A B400 # islice('ABCDEFG', 2, 4) → C D401 # islice('ABCDEFG', 2, None) → C D E F G402 # islice('ABCDEFG', 0, None, 2) → A C E G403404 s = slice(*args)405 start = 0 if s.start is None else s.start406 stop = s.stop407 step = 1 if s.step is None else s.step408 if start < 0 or (stop is not None and stop < 0) or step <= 0:409 raise ValueError410411 indices = count() if stop is None else range(max(start, stop))412 next_i = start413 for i, element in zip(indices, iterable):414 if i == next_i:415 yield element416 next_i += step417```418419Если входной объект является итератором, то полное потребление *islice* продвигает входной итератор на `max(start, stop)` шагов независимо от значения *step*.420421#### `itertools.pairwise(iterable)`422423Возвращает последовательные перекрывающиеся пары, взятые из входного *iterable*.424425Количество кортежей из двух элементов в выходном итераторе будет на один меньше, чем количество входных элементов. Он будет пустым, если входной итерируемый объект содержит менее двух значений.426427Примерно эквивалентно:428429```python430def pairwise(iterable):431 # pairwise('ABCDEFG') → AB BC CD DE EF FG432433 iterator = iter(iterable)434 a = next(iterator, None)435436 for b in iterator:437 yield a, b438 a = b439```440441Добавлено в версии 3.10.442443#### `itertools.permutations(iterable, r=None)`444445Возвращает последовательные *r*-элементные [перестановки элементов](https://python-all.ru/3.13/library/itertools.html) из *iterable*.446447Если *r* не указан или равен `None`, то *r* по умолчанию равен длине *iterable* и генерируются все возможные перестановки полной длины.448449Результат является подпоследовательностью [`product()`](https://python-all.ru/3.13/library/itertools.html#itertools.product), из которой отфильтрованы записи с повторяющимися элементами. Длина результата определяется [`math.perm()`](https://python-all.ru/3.13/library/math.html#math.perm), который вычисляет `n! / (n - r)!`, когда `0 ≤ r ≤ n`, или ноль, когда `r > n`.450451Кортежи перестановок выдаются в лексикографическом порядке в соответствии с порядком входного *iterable*. Если входной *iterable* отсортирован, выходные кортежи будут созданы в отсортированном порядке.452453Элементы считаются уникальными на основе их позиции, а не значения. Если входные элементы уникальны, то в перестановке не будет повторяющихся значений.454455Примерно эквивалентно:456457```python458def permutations(iterable, r=None):459 # permutations('ABCD', 2) → AB AC AD BA BC BD CA CB CD DA DB DC460 # permutations(range(3)) → 012 021 102 120 201 210461462 pool = tuple(iterable)463 n = len(pool)464 r = n if r is None else r465 if r > n:466 return467468 indices = list(range(n))469 cycles = list(range(n, n-r, -1))470 yield tuple(pool[i] for i in indices[:r])471472 while n:473 for i in reversed(range(r)):474 cycles[i] -= 1475 if cycles[i] == 0:476 indices[i:] = indices[i+1:] + indices[i:i+1]477 cycles[i] = n - i478 else:479 j = cycles[i]480 indices[i], indices[-j] = indices[-j], indices[i]481 yield tuple(pool[i] for i in indices[:r])482 break483 else:484 return485```486487#### `itertools.product(*iterables, repeat=1)`488489[Декартово произведение](https://python-all.ru/3.13/library/itertools.html) входных итерируемых объектов.490491Примерно эквивалентно вложенным циклам for в генераторном выражении. Например, `product(A, B)` возвращает то же, что и `((x,y) for x in A for y in B)`.492493Вложенные циклы работают как одометр: самый правый элемент увеличивается на каждой итерации. Этот шаблон создает лексикографический порядок, так что если входные итерируемые объекты отсортированы, кортежи произведения выдаются в отсортированном порядке.494495Чтобы вычислить произведение итерируемого объекта на самого себя, укажите количество повторений с помощью необязательного именованного аргумента *repeat*. Например, `product(A, repeat=4)` эквивалентно `product(A, A, A, A)`.496497Эта функция примерно эквивалентна следующему коду, за исключением того, что реальная реализация не накапливает промежуточные результаты в памяти:498499```python500def product(*iterables, repeat=1):501 # product('ABCD', 'xy') → Ax Ay Bx By Cx Cy Dx Dy502 # product(range(2), repeat=3) → 000 001 010 011 100 101 110 111503504 if repeat < 0:505 raise ValueError('repeat argument cannot be negative')506 pools = [tuple(pool) for pool in iterables] * repeat507508 result = [[]]509 for pool in pools:510 result = [x+[y] for x in result for y in pool]511512 for prod in result:513 yield tuple(prod)514```515516Перед запуском `product()` полностью потребляет входные итерируемые объекты, сохраняя пулы значений в памяти для генерации произведений. Соответственно, она полезна только для конечных входных данных.517518#### `itertools.repeat(object[, times])`519520Создает итератор, который снова и снова возвращает *object*. Работает бесконечно, если не указан аргумент *times*.521522Примерно эквивалентно:523524```python525def repeat(object, times=None):526 # repeat(10, 3) → 10 10 10527 if times is None:528 while True:529 yield object530 else:531 for i in range(times):532 yield object533```534535Обычное применение *repeat* – передача потока постоянных значений в *map* или *zip*:536537```pycon538>>> list(map(pow, range(10), repeat(2)))539[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]540```541542#### `itertools.starmap(function, iterable)`543544Создаёт итератор, который вычисляет *функцию*, используя аргументы, полученные из *итерируемого объекта*. Используется вместо [`map()`](https://python-all.ru/3.13/library/functions.html#map), когда параметры аргументов уже «предварительно упакованы» в кортежи.545546Различие между [`map()`](https://python-all.ru/3.13/library/functions.html#map) и `starmap()` аналогично различию между `function(a,b)` и `function(*c)`. Примерно эквивалентно:547548```python549def starmap(function, iterable):550 # starmap(pow, [(2,5), (3,2), (10,3)]) → 32 9 1000551 for args in iterable:552 yield function(*args)553```554555#### `itertools.takewhile(predicate, iterable)`556557Создаёт итератор, который возвращает элементы из *итерируемого объекта* до тех пор, пока *предикат* истинен. Примерно эквивалентно:558559```python560def takewhile(predicate, iterable):561 # takewhile(lambda x: x<5, [1,4,6,3,8]) → 1 4562 for x in iterable:563 if not predicate(x):564 break565 yield x566```567568Обратите внимание: элемент, который первым не удовлетворяет условию предиката, потребляется из входного итератора, и доступа к нему нет. Это может быть проблемой, если приложение хочет продолжить потребление входного итератора после того, как *takewhile* отработал до полного исчерпания. Чтобы обойти эту проблему, рассмотрите возможность использования [more-itertools.before\_and\_after()](https://python-all.ru/3.13/library/itertools.html) вместо этого.569570#### `itertools.tee(iterable, n=2)`571572Возвращает *n* независимых итераторов из одного итерируемого объекта.573574Примерно эквивалентно:575576```python577def tee(iterable, n=2):578 if n < 0:579 raise ValueError580 if n == 0:581 return ()582 iterator = _tee(iterable)583 result = [iterator]584 for _ in range(n - 1):585 result.append(_tee(iterator))586 return tuple(result)587588class _tee:589590 def __init__(self, iterable):591 it = iter(iterable)592 if isinstance(it, _tee):593 self.iterator = it.iterator594 self.link = it.link595 else:596 self.iterator = it597 self.link = [None, None]598599 def __iter__(self):600 return self601602 def __next__(self):603 link = self.link604 if link[1] is None:605 link[0] = next(self.iterator)606 link[1] = [None, None]607 value, self.link = link608 return value609```610611Если входной *итерируемый объект* уже является объектом-итератором tee, все элементы возвращаемого кортежа создаются так, как если бы они были произведены upstream-вызовом `tee()`. Этот «шаг уплощения» позволяет вложенным вызовам `tee()` использовать одну и ту же базовую цепочку данных и выполнять один шаг обновления вместо цепочки вызовов.612613Свойство уплощения делает итераторы tee эффективно просматриваемыми:614615```python616def lookahead(tee_iterator):617 "Return the next value without moving the input forward"618 [forked_iterator] = tee(tee_iterator, 1)619 return next(forked_iterator)620```621622```pycon623>>> iterator = iter('abcdef')624>>> [iterator] = tee(iterator, 1) # Сделать входные данные просматриваемыми (peekable)625>>> next(iterator) # Продвинуть итератор вперед626'a'627>>> lookahead(iterator) # Проверить следующее значение628'b'629>>> next(iterator) # Продолжить движение вперед630'b'631```632633Итераторы `tee` не являются потокобезопасными. Исключение [`RuntimeError`](https://python-all.ru/3.13/library/exceptions.html#RuntimeError) может быть возбуждено при одновременном использовании итераторов, возвращённых одним вызовом `tee()`, даже если исходный *итерируемый объект* потокобезопасен.634635Этот инструмент итерации может потребовать значительного вспомогательного хранилища (в зависимости от объёма временных данных, которые необходимо сохранить). В общем случае, если один итератор использует большую часть или все данные до того, как запустится другой итератор, быстрее использовать [`list()`](https://python-all.ru/3.13/library/stdtypes.html#list) вместо `tee()`.636637#### `itertools.zip_longest(*iterables, fillvalue=None)`638639Создаёт итератор, который объединяет элементы из каждого *итерируемого объекта*.640641Если итерируемые объекты имеют разную длину, недостающие значения заполняются с помощью *fillvalue*. Если не указан, *fillvalue* по умолчанию равен `None`.642643Итерация продолжается, пока самый длинный итерируемый объект не будет исчерпан.644645Примерно эквивалентно:646647```python648def zip_longest(*iterables, fillvalue=None):649 # zip_longest('ABCD', 'xy', fillvalue='-') → Ax By C- D-650651 iterators = list(map(iter, iterables))652 num_active = len(iterators)653 if not num_active:654 return655656 while True:657 values = []658 for i, iterator in enumerate(iterators):659 try:660 value = next(iterator)661 except StopIteration:662 num_active -= 1663 if not num_active:664 return665 iterators[i] = repeat(fillvalue)666 value = fillvalue667 values.append(value)668 yield tuple(values)669```670671Если один из итерируемых объектов потенциально бесконечен, то функция `zip_longest()` должна быть обёрнута чем-то, что ограничивает количество вызовов (например, [`islice()`](https://python-all.ru/3.13/library/itertools.html#itertools.islice) или [`takewhile()`](https://python-all.ru/3.13/library/itertools.html#itertools.takewhile)).672673## Рецепты itertools674675В этом разделе представлены рецепты для создания расширенного набора инструментов с использованием существующих itertools в качестве строительных блоков.676677Основная цель рецептов itertools – образовательная. Рецепты демонстрируют различные способы мышления об отдельных инструментах – например, что `chain.from_iterable` связано с концепцией уплощения. Рецепты также дают идеи о том, как инструменты можно комбинировать – например, как `starmap()` и `repeat()` могут работать вместе. Рецепты также показывают шаблоны использования itertools с модулями [`operator`](https://python-all.ru/3.13/library/operator.html#module-operator) и [`collections`](https://python-all.ru/3.13/library/collections.html#module-collections), а также со встроенными itertools, такими как `map()`, `filter()`, `reversed()` и `enumerate()`.678679Второстепенная цель рецептов – служить инкубатором. `accumulate()`, `compress()` и `pairwise()` изначально были рецептами. В настоящее время рецепты `sliding_window()`, `iter_index()` и `sieve()` тестируются, чтобы проверить, оправдают ли они себя.680681Практически все эти и многие другие рецепты можно установить из проекта [more-itertools](https://python-all.ru/3.13/library/itertools.html), доступного на Python Package Index:682683```python684python -m pip install more-itertools685```686687Многие рецепты обеспечивают такую же высокую производительность, как и базовый набор инструментов. Превосходная производительность по памяти достигается за счёт обработки элементов по одному, а не загрузки всего итерируемого объекта в память сразу. Объём кода сохраняется небольшим за счёт связывания инструментов в [функциональном стиле](https://python-all.ru/3.13/library/itertools.html). Высокая скорость сохраняется благодаря предпочтению «векторизованных» строительных блоков перед использованием циклов for и [генераторов](https://python-all.ru/3.13/glossary.html#term-generator), которые влекут накладные расходы интерпретатора.688689```python690from collections import Counter, deque691from contextlib import suppress692from functools import reduce693from math import comb, prod, sumprod, isqrt694from operator import itemgetter, getitem, mul, neg, truediv695696def take(n, iterable):697 "Return first n items of the iterable as a list."698 return list(islice(iterable, n))699700def prepend(value, iterable):701 "Prepend a single value in front of an iterable."702 # prepend(1, [2, 3, 4]) → 1 2 3 4703 return chain([value], iterable)704705def running_mean(iterable):706 "Yield the average of all values seen so far."707 # running_mean([8.5, 9.5, 7.5, 6.5]) → 8.5 9.0 8.5 8.0708 return map(truediv, accumulate(iterable), count(1))709710def repeatfunc(function, times=None, *args):711 "Repeat calls to a function with specified arguments."712 if times is None:713 return starmap(function, repeat(args))714 return starmap(function, repeat(args, times))715716def flatten(list_of_lists):717 "Flatten one level of nesting."718 return chain.from_iterable(list_of_lists)719720def ncycles(iterable, n):721 "Returns the sequence elements n times."722 return chain.from_iterable(repeat(tuple(iterable), n))723724def loops(n):725 "Loop n times. Like range(n) but without creating integers."726 # for _ in loops(100): ...727 return repeat(None, n)728729def tail(n, iterable):730 "Return an iterator over the last n items."731 # tail(3, 'ABCDEFG') → E F G732 return iter(deque(iterable, maxlen=n))733734def consume(iterator, n=None):735 "Advance the iterator n-steps ahead. If n is None, consume entirely."736 # Используйте функции, потребляющие итераторы на скорости C.737 if n is None:738 deque(iterator, maxlen=0)739 else:740 next(islice(iterator, n, n), None)741742def nth(iterable, n, default=None):743 "Returns the nth item or a default value."744 return next(islice(iterable, n, None), default)745746def quantify(iterable, predicate=bool):747 "Given a predicate that returns True or False, count the True results."748 return sum(map(predicate, iterable))749750def first_true(iterable, default=False, predicate=None):751 "Returns the first true value or the *default* if there is no true value."752 # first_true([a,b,c], x) → a or b or c or x753 # first_true([a,b], x, f) → a if f(a) else b if f(b) else x754 return next(filter(predicate, iterable), default)755756def all_equal(iterable, key=None):757 "Returns True if all the elements are equal to each other."758 # all_equal('4٤௪౪໔', key=int) → True759 return len(take(2, groupby(iterable, key))) <= 1760761def unique_justseen(iterable, key=None):762 "Yield unique elements, preserving order. Remember only the element just seen."763 # unique_justseen('AAAABBBCCDAABBB') → A B C D A B764 # unique_justseen('ABBcCAD', str.casefold) → A B c A D765 if key is None:766 return map(itemgetter(0), groupby(iterable))767 return map(next, map(itemgetter(1), groupby(iterable, key)))768769def unique_everseen(iterable, key=None):770 "Yield unique elements, preserving order. Remember all elements ever seen."771 # unique_everseen('AAAABBBCCDAABBB') → A B C D772 # unique_everseen('ABBcCAD', str.casefold) → A B c D773 seen = set()774 if key is None:775 for element in filterfalse(seen.__contains__, iterable):776 seen.add(element)777 yield element778 else:779 for element in iterable:780 k = key(element)781 if k not in seen:782 seen.add(k)783 yield element784785def unique(iterable, key=None, reverse=False):786 "Yield unique elements in sorted order. Supports unhashable inputs."787 # unique([[1, 2], [3, 4], [1, 2]]) → [1, 2] [3, 4]788 sequenced = sorted(iterable, key=key, reverse=reverse)789 return unique_justseen(sequenced, key=key)790791def sliding_window(iterable, n):792 "Collect data into overlapping fixed-length chunks or blocks."793 # sliding_window('ABCDEFG', 4) → ABCD BCDE CDEF DEFG794 iterator = iter(iterable)795 window = deque(islice(iterator, n - 1), maxlen=n)796 for x in iterator:797 window.append(x)798 yield tuple(window)799800def grouper(iterable, n, *, incomplete='fill', fillvalue=None):801 "Collect data into non-overlapping fixed-length chunks or blocks."802 # grouper('ABCDEFG', 3, fillvalue='x') → ABC DEF Gxx803 # grouper('ABCDEFG', 3, incomplete='strict') → ABC DEF ValueError804 # grouper('ABCDEFG', 3, incomplete='ignore') → ABC DEF805 iterators = [iter(iterable)] * n806 match incomplete:807 case 'fill':808 return zip_longest(*iterators, fillvalue=fillvalue)809 case 'strict':810 return zip(*iterators, strict=True)811 case 'ignore':812 return zip(*iterators)813 case _:814 raise ValueError('Expected fill, strict, or ignore')815816def roundrobin(*iterables):817 "Visit input iterables in a cycle until each is exhausted."818 # roundrobin('ABC', 'D', 'EF') → A D E B F C819 # Алгоритм Джорджа Саккиса820 iterators = map(iter, iterables)821 for num_active in range(len(iterables), 0, -1):822 iterators = cycle(islice(iterators, num_active))823 yield from map(next, iterators)824825def subslices(seq):826 "Return all contiguous non-empty subslices of a sequence."827 # subslices('ABCD') → A AB ABC ABCD B BC BCD C CD D828 slices = starmap(slice, combinations(range(len(seq) + 1), 2))829 return map(getitem, repeat(seq), slices)830831def iter_index(iterable, value, start=0, stop=None):832 "Return indices where a value occurs in a sequence or iterable."833 # iter_index('AABCADEAF', 'A') → 0 1 4 7834 seq_index = getattr(iterable, 'index', None)835 if seq_index is None:836 iterator = islice(iterable, start, stop)837 for i, element in enumerate(iterator, start):838 if element is value or element == value:839 yield i840 else:841 stop = len(iterable) if stop is None else stop842 i = start843 with suppress(ValueError):844 while True:845 yield (i := seq_index(value, i, stop))846 i += 1847848def iter_except(function, exception, first=None):849 "Convert a call-until-exception interface to an iterator interface."850 # iter_except(d.popitem, KeyError) → неблокирующий итератор словаря851 with suppress(exception):852 if first is not None:853 yield first()854 while True:855 yield function()856```857858Следующие рецепты имеют более математическую направленность:859860```python861def multinomial(*counts):862 "Number of distinct arrangements of a multiset."863 # Counter('abracadabra').values() → 5 2 2 1 1864 # multinomial(5, 2, 2, 1, 1) → 83160865 return prod(map(comb, accumulate(counts), counts))866867def powerset(iterable):868 "Subsequences of the iterable from shortest to longest."869 # powerset([1,2,3]) → () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)870 s = list(iterable)871 return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))872873def sum_of_squares(iterable):874 "Add up the squares of the input values."875 # sum_of_squares([10, 20, 30]) → 1400876 return sumprod(*tee(iterable))877878def reshape(matrix, columns):879 "Reshape a 2-D matrix to have a given number of columns."880 # reshape([(0, 1), (2, 3), (4, 5)], 3) → (0, 1, 2), (3, 4, 5)881 return batched(chain.from_iterable(matrix), columns, strict=True)882883def transpose(matrix):884 "Swap the rows and columns of a 2-D matrix."885 # transpose([(1, 2, 3), (11, 22, 33)]) → (1, 11) (2, 22) (3, 33)886 return zip(*matrix, strict=True)887888def matmul(m1, m2):889 "Multiply two matrices."890 # matmul([(7, 5), (3, 5)], [(2, 5), (7, 9)]) → (49, 80), (41, 60)891 n = len(m2[0])892 return batched(starmap(sumprod, product(m1, transpose(m2))), n)893894def convolve(signal, kernel):895 """Дискретная линейная свёртка двух итерируемых объектов.896 Эквивалентно умножению многочленов.897898 Свёртки математически коммутативны; однако входные данные899 вычисляются по-разному. Сигнал потребляется лениво и может быть900 бесконечным. Ядро полностью потребляется до начала вычислений.901902 Статья: https://betterexplained.com/articles/intuitive-convolution/903 Видео: https://www.youtube.com/watch?v=KuXjwB4LzSA904 """905 # convolve([1, -1, -20], [1, -3]) → 1 -4 -17 60906 # convolve(data, [0.25, 0.25, 0.25, 0.25]) → Скользящее среднее (размытие)907 # convolve(data, [1/2, 0, -1/2]) → Оценка первой производной908 # convolve(data, [1, -2, 1]) → Оценка второй производной909 kernel = tuple(kernel)[::-1]910 n = len(kernel)911 padded_signal = chain(repeat(0, n-1), signal, repeat(0, n-1))912 windowed_signal = sliding_window(padded_signal, n)913 return map(sumprod, repeat(kernel), windowed_signal)914915def polynomial_from_roots(roots):916 """Вычисляет коэффициенты многочлена по его корням.917918 (x - 5) (x + 4) (x - 3) раскрывается в: x³ -4x² -17x + 60919 """920 # polynomial_from_roots([5, -4, 3]) → [1, -4, -17, 60]921 factors = zip(repeat(1), map(neg, roots))922 return list(reduce(convolve, factors, [1]))923924def polynomial_eval(coefficients, x):925 """Вычисляет значение многочлена в заданной точке.926927 Вычисляет с лучшей численной устойчивостью, чем метод Горнера.928 """929 # Вычислить x³ -4x² -17x + 60 при x = 5930 # polynomial_eval([1, -4, -17, 60], x=5) → 0931 n = len(coefficients)932 if not n:933 return type(x)(0)934 powers = map(pow, repeat(x), reversed(range(n)))935 return sumprod(coefficients, powers)936937def polynomial_derivative(coefficients):938 """Вычисляет первую производную многочлена.939940 f(x) = x³ -4x² -17x + 60941 f'(x) = 3x² -8x -17942 """943 # polynomial_derivative([1, -4, -17, 60]) → [3, -8, -17]944 n = len(coefficients)945 powers = reversed(range(1, n))946 return list(map(mul, coefficients, powers))947948def sieve(n):949 "Primes less than n."950 # sieve(30) → 2 3 5 7 11 13 17 19 23 29951 if n > 2:952 yield 2953 data = bytearray((0, 1)) * (n // 2)954 for p in iter_index(data, 1, start=3, stop=isqrt(n) + 1):955 data[p*p : n : p+p] = bytes(len(range(p*p, n, p+p)))956 yield from iter_index(data, 1, start=3)957958def factor(n):959 "Prime factors of n."960 # factor(99) → 3 3 11961 # factor(1_000_000_000_000_007) → 47 59 360620266859962 # factor(1_000_000_000_000_403) → 1000000000000403963 for prime in sieve(isqrt(n) + 1):964 while not n % prime:965 yield prime966 n //= prime967 if n == 1:968 return969 if n > 1:970 yield n971972def is_prime(n):973 "Return True if n is prime."974 # is_prime(1_000_000_000_000_403) → True975 return n > 1 and next(factor(n)) == n976977def totient(n):978 "Count of natural numbers up to n that are coprime to n."979 # https://mathworld.wolfram.com/TotientFunction.html980 # totient(12) → 4 потому что len([1, 5, 7, 11]) == 4981 for prime in set(factor(n)):982 n -= n // prime983 return n984```985