itertools.md
1> **Источник:** https://python-all.ru/3.15/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.15/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.15/library/functions.html#map) и [`count()`](https://python-all.ru/3.15/library/itertools.html#itertools.count) для получения `map(f, count())`.1617**Основные итераторы:**1819| Итератор | Аргументы | Результаты | Пример |20| --- | --- | --- | --- |21| [`accumulate()`](https://python-all.ru/3.15/library/itertools.html#itertools.accumulate) | p \[,func\] | p0, p0+p1, p0+p1+p2, … | `accumulate([1,2,3,4,5]) → 1 3 6 10 15` |22| [`batched()`](https://python-all.ru/3.15/library/itertools.html#itertools.batched) | p, n | (p0, p1, …, p\_n-1), … | `batched('ABCDEFG', n=3) → ABC DEF G` |23| [`chain()`](https://python-all.ru/3.15/library/itertools.html#itertools.chain) | p, q, … | p0, p1, … plast, q0, q1, … | `chain('ABC', 'DEF') → A B C D E F` |24| [`chain.from_iterable()`](https://python-all.ru/3.15/library/itertools.html#itertools.chain.from_iterable) | iterable | p0, p1, … plast, q0, q1, … | `chain.from_iterable(['ABC', 'DEF']) → A B C D E F` |25| [`compress()`](https://python-all.ru/3.15/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` |26| [`count()`](https://python-all.ru/3.15/library/itertools.html#itertools.count) | \[start\[, step\]\] | start, start+step, start+2\*step, … | `count(10) → 10 11 12 13 14 ...` |27| [`cycle()`](https://python-all.ru/3.15/library/itertools.html#itertools.cycle) | p | p0, p1, … plast, p0, p1, … | `cycle('ABCD') → A B C D A B C D ...` |28| [`dropwhile()`](https://python-all.ru/3.15/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` |29| [`filterfalse()`](https://python-all.ru/3.15/library/itertools.html#itertools.filterfalse) | predicate, seq | элементы seq, для которых predicate(elem) не выполняется | `filterfalse(lambda x: x<5, [1,4,6,3,8]) → 6 8` |30| [`groupby()`](https://python-all.ru/3.15/library/itertools.html#itertools.groupby) | iterable\[, key\] | подитераторы, сгруппированные по значению key(v) | `groupby(['A','B','DEF'], len) → (1, A B) (3, DEF)` |31| [`islice()`](https://python-all.ru/3.15/library/itertools.html#itertools.islice) | seq, \[start,\] stop \[, step\] | элементы из seq\[start:stop:step\] | `islice('ABCDEFG', 2, None) → C D E F G` |32| [`pairwise()`](https://python-all.ru/3.15/library/itertools.html#itertools.pairwise) | iterable | (p\[0\], p\[1\]), (p\[1\], p\[2\]) | `pairwise('ABCDEFG') → AB BC CD DE EF FG` |33| [`repeat()`](https://python-all.ru/3.15/library/itertools.html#itertools.repeat) | elem \[,n\] | elem, elem, elem, … бесконечно или до n раз | `repeat(10, 3) → 10 10 10` |34| [`starmap()`](https://python-all.ru/3.15/library/itertools.html#itertools.starmap) | func, seq | func(\*seq\[0\]), func(\*seq\[1\]), … | `starmap(pow, [(2,5), (3,2), (10,3)]) → 32 9 1000` |35| [`takewhile()`](https://python-all.ru/3.15/library/itertools.html#itertools.takewhile) | predicate, seq | seq\[0\], seq\[1\], пока predicate не вернёт ложь | `takewhile(lambda x: x<5, [1,4,6,3,8]) → 1 4` |36| [`tee()`](https://python-all.ru/3.15/library/itertools.html#itertools.tee) | it, n | it1, it2, … itn разделяет один итератор на n | `tee('ABC', 2) → A B C, A B C` |37| [`zip_longest()`](https://python-all.ru/3.15/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-` |3839**Комбинаторные итераторы:**4041| Итератор | Аргументы | Результаты |42| --- | --- | --- |43| [`product()`](https://python-all.ru/3.15/library/itertools.html#itertools.product) | p, q, … \[repeat=1\] | декартово произведение, эквивалентно вложенному циклу for |44| [`permutations()`](https://python-all.ru/3.15/library/itertools.html#itertools.permutations) | p\[, r\] | кортежи длиной r, все возможные перестановки, без повторяющихся элементов |45| [`combinations()`](https://python-all.ru/3.15/library/itertools.html#itertools.combinations) | p, r | кортежи длиной r, в отсортированном порядке, без повторяющихся элементов |46| [`combinations_with_replacement()`](https://python-all.ru/3.15/library/itertools.html#itertools.combinations_with_replacement) | p, r | кортежи длиной r, в отсортированном порядке, с повторяющимися элементами |4748| Примеры | Результаты |49| --- | --- |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## Функции itertools5657Следующие функции создают и возвращают итераторы. Некоторые из них дают потоки бесконечной длины, поэтому их следует использовать только в функциях или циклах, которые обрезают поток.5859#### `itertools.accumulate(iterable[, function, *, initial=None])`6061Создаёт итератор, возвращающий накопленные суммы или накопленные результаты других бинарных функций.6263Если *function* не указана, по умолчанию используется сложение. *Function* должна принимать два аргумента: накопленное значение и очередной элемент из *iterable*.6465Если указано начальное значение *initial*, накопление начнётся с него, и в результате будет на один элемент больше, чем во входном итерируемом объекте.6667Примерно эквивалентно:6869```python70def accumulate(iterable, function=operator.add, *, initial=None):71 'Return running totals'72 # accumulate([1,2,3,4,5]) → 1 3 6 10 1573 # accumulate([1,2,3,4,5], initial=100) → 100 101 103 106 110 11574 # accumulate([1,2,3,4,5], operator.mul) → 1 2 6 24 1207576 iterator = iter(iterable)77 total = initial78 if initial is None:79 try:80 total = next(iterator)81 except StopIteration:82 return8384 yield total85 for element in iterator:86 total = function(total, element)87 yield total88```8990Чтобы вычислить текущий минимум, задайте *function* равной [`min()`](https://python-all.ru/3.15/library/functions.html#min). Для текущего максимума – *function* [`max()`](https://python-all.ru/3.15/library/functions.html#max). Для текущего произведения – *function* [`operator.mul()`](https://python-all.ru/3.15/library/operator.html#operator.mul). Для построения [таблицы амортизации](https://python-all.ru/3.15/library/itertools.html) накопите проценты и примените платежи:9192```pycon93>>> data = [3, 4, 6, 2, 1, 9, 0, 7, 5, 8]94>>> list(accumulate(data, max)) # текущий максимум95[3, 4, 6, 6, 6, 9, 9, 9, 9, 9]96>>> list(accumulate(data, operator.mul)) # текущее произведение97[3, 12, 72, 144, 144, 1296, 0, 0, 0, 0]9899# Amortize a 5% loan of 1000 with 10 annual payments of 90100>>> update = lambda balance, payment: round(balance * 1.05) - payment101>>> list(accumulate(repeat(90, 10), update, initial=1_000))102[1000, 960, 918, 874, 828, 779, 728, 674, 618, 559, 497]103```104105См. [`functools.reduce()`](https://python-all.ru/3.15/library/functools.html#functools.reduce) – похожая функция, возвращающая только итоговое накопленное значение.106107Добавлено в версии 3.2.108109Изменено в версии 3.3: Добавлен необязательный параметр *function*.110111Изменено в версии 3.8: Добавлен необязательный параметр *initial*.112113#### `itertools.batched(iterable, n, *, strict=False)`114115Группирует данные из *iterable* в кортежи длины *n*. Последняя группа может быть короче *n*.116117Если *strict* равен True, будет вызвано исключение [`ValueError`](https://python-all.ru/3.15/library/exceptions.html#ValueError), если последняя группа короче *n*.118119Перебирает входной iterable и накапливает данные в кортежи размером до *n*. Входные данные обрабатываются лениво – ровно столько, чтобы заполнить одну группу. Результат возвращается сразу, как только группа заполнена или входной iterable исчерпан:120121```pycon122>>> flattened_data = ['roses', 'red', 'violets', 'blue', 'sugar', 'sweet']123>>> unflattened = list(batched(flattened_data, 2))124>>> unflattened125[('roses', 'red'), ('violets', 'blue'), ('sugar', 'sweet')]126```127128Примерно эквивалентно:129130```python131def batched(iterable, n, *, strict=False):132 # batched('ABCDEFG', 3) → ABC DEF G133 if n < 1:134 raise ValueError('n must be at least one')135 iterator = iter(iterable)136 while batch := tuple(islice(iterator, n)):137 if strict and len(batch) != n:138 raise ValueError('batched(): incomplete batch')139 yield batch140```141142Добавлено в версии 3.12.143144Изменено в версии 3.13: Добавлен параметр *strict*.145146#### `itertools.chain(*iterables)`147148Создаёт итератор, который возвращает элементы из первого iterable, пока он не исчерпан, затем переходит к следующему, и так до исчерпания всех. Это объединяет несколько источников данных в один итератор. Примерная реализация:149150```python151def chain(*iterables):152 # chain('ABC', 'DEF') → A B C D E F153 for iterable in iterables:154 yield from iterable155```156157Обратите внимание, что [unpacking in comprehensions](https://python-all.ru/3.15/reference/expressions.html#unpacking-comprehensions) предоставляет аналогичную функциональность, поэтому `list(chain(p, q))` можно записать как `[*s for s in (p, q)]`.158159#### `classmethod chain.from_iterable(iterable)`160161Альтернативный конструктор для [`chain()`](https://python-all.ru/3.15/library/itertools.html#itertools.chain). Получает цепочку входных данных из одного аргумента iterable, который вычисляется лениво. Примерная реализация:162163```python164def from_iterable(iterables):165 # chain.from_iterable(['ABC', 'DEF']) → A B C D E F166 for iterable in iterables:167 yield from iterable168```169170Обратите внимание, что [unpacking in comprehensions](https://python-all.ru/3.15/reference/expressions.html#unpacking-comprehensions) предоставляет аналогичную функциональность, поэтому `list(chain.from_iterable(iterables))` можно записать как `[*s for s in iterables]`.171172#### `itertools.combinations(iterable, r)`173174Возвращает подпоследовательности элементов длины *r* из входного *iterable*.175176Результат является подмножеством [`product()`](https://python-all.ru/3.15/library/itertools.html#itertools.product), в котором оставлены только те элементы, которые являются подпоследовательностями *iterable*. Длина результата задаётся выражением [`math.comb()`](https://python-all.ru/3.15/library/math.html#math.comb), которое равно `n! / r! / (n - r)!`, если `0 ≤ r ≤ n`, или нулю, если `r > n`.177178Кортежи-комбинации порождаются в лексикографическом порядке по порядку входного *iterable*. Если входной *iterable* отсортирован, выходные кортежи также будут отсортированы.179180Элементы считаются уникальными по позиции, а не по значению. Если входные элементы уникальны, то в каждой комбинации не будет повторяющихся значений.181182Примерно эквивалентно:183184```python185def combinations(iterable, r):186 # combinations('ABCD', 2) → AB AC AD BC BD CD187 # combinations(range(4), 3) → 012 013 023 123188189 pool = tuple(iterable)190 n = len(pool)191 if r > n:192 return193 indices = list(range(r))194195 yield tuple(pool[i] for i in indices)196 while True:197 for i in reversed(range(r)):198 if indices[i] != i + n - r:199 break200 else:201 return202 indices[i] += 1203 for j in range(i+1, r):204 indices[j] = indices[j-1] + 1205 yield tuple(pool[i] for i in indices)206```207208#### `itertools.combinations_with_replacement(iterable, r)`209210Возвращает подпоследовательности элементов длины *r* из входного *iterable*, допуская повторение отдельных элементов.211212Результат является подмножеством [`product()`](https://python-all.ru/3.15/library/itertools.html#itertools.product), в котором оставлены только те элементы, которые являются подпоследовательностями (с возможными повторениями) *iterable*. Количество возвращаемых подпоследовательностей равно `(n + r - 1)! / r! / (n - 1)!`, если `n > 0`.213214Кортежи-комбинации порождаются в лексикографическом порядке по порядку входного *iterable*. Если входной *iterable* отсортирован, выходные кортежи будут отсортированы.215216Элементы считаются уникальными по позиции, а не по значению. Если входные элементы уникальны, то порождённые комбинации тоже будут уникальны.217218Примерно эквивалентно:219220```python221def combinations_with_replacement(iterable, r):222 # combinations_with_replacement('ABC', 2) → AA AB AC BB BC CC223224 pool = tuple(iterable)225 n = len(pool)226 if not n and r:227 return228 indices = [0] * r229230 yield tuple(pool[i] for i in indices)231 while True:232 for i in reversed(range(r)):233 if indices[i] != n - 1:234 break235 else:236 return237 indices[i:] = [indices[i] + 1] * (r - i)238 yield tuple(pool[i] for i in indices)239```240241Добавлено в версии 3.1.242243#### `itertools.compress(data, selectors)`244245Создаёт итератор, который возвращает элементы из *data*, для которых соответствующий элемент из *selectors* истинен. Останавливается, когда исчерпан либо *data*, либо *selectors*. Примерная реализация:246247```python248def compress(data, selectors):249 # compress('ABCDEF', [1,0,1,0,1,1]) → A C E F250 return (datum for datum, selector in zip(data, selectors) if selector)251```252253Добавлено в версии 3.1.254255#### `itertools.count(start=0, step=1)`256257Создаёт итератор, возвращающий равномерно расположенные значения, начиная с *start*. Может использоваться с [`map()`](https://python-all.ru/3.15/library/functions.html#map) для генерации последовательных точек данных или с [`zip()`](https://python-all.ru/3.15/library/functions.html#zip) для добавления номеров по порядку. Примерная реализация:258259```python260def count(start=0, step=1):261 # count(10) → 10 11 12 13 14 ...262 # count(2.5, 0.5) → 2.5 3.0 3.5 ...263 n = start264 while True:265 yield n266 n += step267```268269При подсчёте с числами с плавающей точкой иногда лучшей точности можно добиться, используя мультипликативный код, например: `(start + step * i for i in count())`.270271Изменено в версии 3.1: Добавлен аргумент *step* и разрешены нецелые аргументы.272273#### `itertools.cycle(iterable)`274275Создаёт итератор, который возвращает элементы из *iterable* и сохраняет копию каждого. Когда iterable исчерпан, возвращает элементы из сохранённой копии. Повторяется бесконечно. Примерная реализация:276277```python278def cycle(iterable):279 # cycle('ABCD') → A B C D A B C D A B C D ...280281 saved = []282 for element in iterable:283 yield element284 saved.append(element)285286 while saved:287 for element in saved:288 yield element289```290291Этот инструмент может потребовать значительного объёма дополнительной памяти (в зависимости от длины iterable).292293#### `itertools.dropwhile(predicate, iterable)`294295Создаёт итератор, который пропускает элементы из *iterable*, пока *predicate* истинен, а затем возвращает все оставшиеся элементы. Примерная реализация:296297```python298def dropwhile(predicate, iterable):299 # dropwhile(lambda x: x<5, [1,4,6,3,8]) → 6 3 8300301 iterator = iter(iterable)302 for x in iterator:303 if not predicate(x):304 yield x305 break306307 for x in iterator:308 yield x309```310311Обратите внимание: этот итератор не выдаёт *ни одного* элемента, пока предикат впервые не станет ложным, поэтому время запуска может быть большим.312313#### `itertools.filterfalse(predicate, iterable)`314315Создаёт итератор, который фильтрует элементы из *iterable*, возвращая только те, для которых *predicate* возвращает ложное значение. Если *predicate* равен `None`, возвращает элементы, которые являются ложными. Примерная реализация:316317```python318def filterfalse(predicate, iterable):319 # filterfalse(lambda x: x<5, [1,4,6,3,8]) → 6 8320321 if predicate is None:322 predicate = bool323324 for x in iterable:325 if not predicate(x):326 yield x327```328329#### `itertools.groupby(iterable, key=None)`330331Make 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.332333Работа `groupby()` аналогична фильтру `uniq` в Unix. Она создает разрыв или новую группу каждый раз, когда изменяется значение ключевой функции (поэтому обычно необходимо отсортировать данные с помощью той же ключевой функции). Такое поведение отличается от SQL GROUP BY, которая объединяет общие элементы независимо от порядка их ввода.334335Возвращаемая группа сама является итератором, который использует общий исходный итерируемый объект с `groupby()`. Поскольку источник общий, при продвижении объекта `groupby()` предыдущая группа перестает быть видимой. Поэтому, если эти данные понадобятся позже, их следует сохранить в виде списка:336337```python338groups = []339uniquekeys = []340data = sorted(data, key=keyfunc)341for k, g in groupby(data, keyfunc):342 groups.append(list(g)) # Сохранить групповой итератор как список343 uniquekeys.append(k)344```345346`groupby()` примерно эквивалентно:347348```python349def groupby(iterable, key=None):350 # [k for k, g in groupby('AAAABBBCCDAABBB')] → A B C D A B351 # [list(g) for k, g in groupby('AAAABBBCCD')] → AAAA BBB CC D352353 keyfunc = (lambda x: x) if key is None else key354 iterator = iter(iterable)355 exhausted = False356357 def _grouper(target_key):358 nonlocal curr_value, curr_key, exhausted359 yield curr_value360 for curr_value in iterator:361 curr_key = keyfunc(curr_value)362 if curr_key != target_key:363 return364 yield curr_value365 exhausted = True366367 try:368 curr_value = next(iterator)369 except StopIteration:370 return371 curr_key = keyfunc(curr_value)372373 while not exhausted:374 target_key = curr_key375 curr_group = _grouper(target_key)376 yield curr_key, curr_group377 if curr_key == target_key:378 for _ in curr_group:379 pass380```381382#### `itertools.islice(iterable, stop)`383384#### `itertools.islice(iterable, start, stop[, step])`385386Создает итератор, который возвращает выбранные элементы из итерируемого объекта. Работает как срез последовательности, но не поддерживает отрицательные значения для *start*, *stop* или *step*.387388Если *start* равен нулю или `None`, итерация начинается с нуля. В противном случае элементы из итерируемого объекта пропускаются до достижения *start*.389390Если *stop* равен `None`, итерация продолжается до тех пор, пока входной объект не будет исчерпан. В противном случае она останавливается на указанной позиции.391392Если *step* равен `None`, шаг по умолчанию равен единице. Элементы возвращаются последовательно, если только *step* не больше единицы, что приводит к пропуску элементов.393394Примерно эквивалентно:395396```python397def islice(iterable, *args):398 # islice('ABCDEFG', 2) → A B399 # islice('ABCDEFG', 2, 4) → C D400 # islice('ABCDEFG', 2, None) → C D E F G401 # islice('ABCDEFG', 0, None, 2) → A C E G402403 s = slice(*args)404 start = 0 if s.start is None else s.start405 stop = s.stop406 step = 1 if s.step is None else s.step407 if start < 0 or (stop is not None and stop < 0) or step <= 0:408 raise ValueError409410 indices = count() if stop is None else range(max(start, stop))411 next_i = start412 for i, element in zip(indices, iterable):413 if i == next_i:414 yield element415 next_i += step416```417418Если входной объект является итератором, то полное потребление *islice* продвигает входной итератор на `max(start, stop)` шагов независимо от значения *step*.419420#### `itertools.pairwise(iterable)`421422Возвращает последовательные перекрывающиеся пары, взятые из входного *iterable*.423424Количество кортежей из двух элементов в выходном итераторе будет на один меньше, чем количество входных элементов. Он будет пустым, если входной итерируемый объект содержит менее двух значений.425426Примерно эквивалентно:427428```python429def pairwise(iterable):430 # pairwise('ABCDEFG') → AB BC CD DE EF FG431432 iterator = iter(iterable)433 a = next(iterator, None)434435 for b in iterator:436 yield a, b437 a = b438```439440Добавлено в версии 3.10.441442#### `itertools.permutations(iterable, r=None)`443444Возвращает последовательные *r*-элементные [перестановки элементов](https://python-all.ru/3.15/library/itertools.html) из *iterable*.445446Если *r* не указан или равен `None`, то *r* по умолчанию равен длине *iterable* и генерируются все возможные перестановки полной длины.447448Результат является подпоследовательностью [`product()`](https://python-all.ru/3.15/library/itertools.html#itertools.product), из которой отфильтрованы записи с повторяющимися элементами. Длина результата определяется [`math.perm()`](https://python-all.ru/3.15/library/math.html#math.perm), который вычисляет `n! / (n - r)!`, когда `0 ≤ r ≤ n`, или ноль, когда `r > n`.449450Кортежи перестановок выдаются в лексикографическом порядке в соответствии с порядком входного *iterable*. Если входной *iterable* отсортирован, выходные кортежи будут созданы в отсортированном порядке.451452Элементы считаются уникальными на основе их позиции, а не значения. Если входные элементы уникальны, то в перестановке не будет повторяющихся значений.453454Примерно эквивалентно:455456```python457def permutations(iterable, r=None):458 # permutations('ABCD', 2) → AB AC AD BA BC BD CA CB CD DA DB DC459 # permutations(range(3)) → 012 021 102 120 201 210460461 pool = tuple(iterable)462 n = len(pool)463 r = n if r is None else r464 if r > n:465 return466467 indices = list(range(n))468 cycles = list(range(n, n-r, -1))469 yield tuple(pool[i] for i in indices[:r])470471 while n:472 for i in reversed(range(r)):473 cycles[i] -= 1474 if cycles[i] == 0:475 indices[i:] = indices[i+1:] + indices[i:i+1]476 cycles[i] = n - i477 else:478 j = cycles[i]479 indices[i], indices[-j] = indices[-j], indices[i]480 yield tuple(pool[i] for i in indices[:r])481 break482 else:483 return484```485486#### `itertools.product(*iterables, repeat=1)`487488[Декартово произведение](https://python-all.ru/3.15/library/itertools.html) входных итерируемых объектов.489490Примерно эквивалентно вложенным циклам for в генераторном выражении. Например, `product(A, B)` возвращает то же, что и `((x,y) for x in A for y in B)`.491492Вложенные циклы работают как одометр: самый правый элемент увеличивается на каждой итерации. Этот шаблон создает лексикографический порядок, так что если входные итерируемые объекты отсортированы, кортежи произведения выдаются в отсортированном порядке.493494Чтобы вычислить произведение итерируемого объекта на самого себя, укажите количество повторений с помощью необязательного именованного аргумента *repeat*. Например, `product(A, repeat=4)` эквивалентно `product(A, A, A, A)`.495496Эта функция примерно эквивалентна следующему коду, за исключением того, что реальная реализация не накапливает промежуточные результаты в памяти:497498```python499def product(*iterables, repeat=1):500 # product('ABCD', 'xy') → Ax Ay Bx By Cx Cy Dx Dy501 # product(range(2), repeat=3) → 000 001 010 011 100 101 110 111502503 if repeat < 0:504 raise ValueError('repeat argument cannot be negative')505 pools = [tuple(pool) for pool in iterables] * repeat506507 result = [[]]508 for pool in pools:509 result = [x+[y] for x in result for y in pool]510511 for prod in result:512 yield tuple(prod)513```514515Перед запуском `product()` полностью потребляет входные итерируемые объекты, сохраняя пулы значений в памяти для генерации произведений. Соответственно, она полезна только для конечных входных данных.516517#### `itertools.repeat(object[, times])`518519Создает итератор, который снова и снова возвращает *object*. Работает бесконечно, если не указан аргумент *times*.520521Примерно эквивалентно:522523```python524def repeat(object, times=None):525 # repeat(10, 3) → 10 10 10526 if times is None:527 while True:528 yield object529 else:530 for i in range(times):531 yield object532```533534Обычное применение *repeat* – передача потока постоянных значений в *map* или *zip*:535536```pycon537>>> list(map(pow, range(10), repeat(2)))538[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]539```540541#### `itertools.starmap(function, iterable)`542543Создаёт итератор, который вычисляет *функцию*, используя аргументы, полученные из *итерируемого объекта*. Используется вместо [`map()`](https://python-all.ru/3.15/library/functions.html#map), когда параметры аргументов уже «предварительно упакованы» в кортежи.544545Различие между [`map()`](https://python-all.ru/3.15/library/functions.html#map) и `starmap()` аналогично различию между `function(a,b)` и `function(*c)`. Примерно эквивалентно:546547```python548def starmap(function, iterable):549 # starmap(pow, [(2,5), (3,2), (10,3)]) → 32 9 1000550 for args in iterable:551 yield function(*args)552```553554#### `itertools.takewhile(predicate, iterable)`555556Создаёт итератор, который возвращает элементы из *итерируемого объекта* до тех пор, пока *предикат* истинен. Примерно эквивалентно:557558```python559def takewhile(predicate, iterable):560 # takewhile(lambda x: x<5, [1,4,6,3,8]) → 1 4561 for x in iterable:562 if not predicate(x):563 break564 yield x565```566567Обратите внимание: элемент, который первым не удовлетворяет условию предиката, потребляется из входного итератора, и доступа к нему нет. Это может быть проблемой, если приложение хочет продолжить потребление входного итератора после того, как *takewhile* отработал до полного исчерпания. Чтобы обойти эту проблему, рассмотрите возможность использования [more-itertools.before\_and\_after()](https://python-all.ru/3.15/library/itertools.html) вместо этого.568569#### `itertools.tee(iterable, n=2)`570571Возвращает *n* независимых итераторов из одного итерируемого объекта.572573Примерно эквивалентно:574575```python576def tee(iterable, n=2):577 if n < 0:578 raise ValueError579 if n == 0:580 return ()581 iterator = _tee(iterable)582 result = [iterator]583 for _ in range(n - 1):584 result.append(_tee(iterator))585 return tuple(result)586587class _tee:588589 def __init__(self, iterable):590 it = iter(iterable)591 if isinstance(it, _tee):592 self.iterator = it.iterator593 self.link = it.link594 else:595 self.iterator = it596 self.link = [None, None]597598 def __iter__(self):599 return self600601 def __next__(self):602 link = self.link603 if link[1] is None:604 link[0] = next(self.iterator)605 link[1] = [None, None]606 value, self.link = link607 return value608```609610Если входной *итерируемый объект* уже является объектом-итератором tee, все элементы возвращаемого кортежа создаются так, как если бы они были произведены upstream-вызовом `tee()`. Этот «шаг уплощения» позволяет вложенным вызовам `tee()` использовать одну и ту же базовую цепочку данных и выполнять один шаг обновления вместо цепочки вызовов.611612Свойство уплощения делает итераторы tee эффективно просматриваемыми:613614```python615def lookahead(tee_iterator):616 "Return the next value without moving the input forward"617 [forked_iterator] = tee(tee_iterator, 1)618 return next(forked_iterator)619```620621```pycon622>>> iterator = iter('abcdef')623>>> [iterator] = tee(iterator, 1) # Сделать входные данные просматриваемыми (peekable)624>>> next(iterator) # Продвинуть итератор вперед625'a'626>>> lookahead(iterator) # Проверить следующее значение627'b'628>>> next(iterator) # Продолжить движение вперед629'b'630```631632Итераторы `tee` не являются потокобезопасными. Исключение [`RuntimeError`](https://python-all.ru/3.15/library/exceptions.html#RuntimeError) может быть возбуждено при одновременном использовании итераторов, возвращённых одним вызовом `tee()`, даже если исходный *итерируемый объект* потокобезопасен.633634Этот инструмент итерации может потребовать значительного вспомогательного хранилища (в зависимости от объёма временных данных, которые необходимо сохранить). В общем случае, если один итератор использует большую часть или все данные до того, как запустится другой итератор, быстрее использовать [`list()`](https://python-all.ru/3.15/library/stdtypes.html#list) вместо `tee()`.635636#### `itertools.zip_longest(*iterables, fillvalue=None)`637638Создаёт итератор, который объединяет элементы из каждого *итерируемого объекта*.639640Если итерируемые объекты имеют разную длину, недостающие значения заполняются с помощью *fillvalue*. Если не указан, *fillvalue* по умолчанию равен `None`.641642Итерация продолжается, пока самый длинный итерируемый объект не будет исчерпан.643644Примерно эквивалентно:645646```python647def zip_longest(*iterables, fillvalue=None):648 # zip_longest('ABCD', 'xy', fillvalue='-') → Ax By C- D-649650 iterators = list(map(iter, iterables))651 num_active = len(iterators)652 if not num_active:653 return654655 while True:656 values = []657 for i, iterator in enumerate(iterators):658 try:659 value = next(iterator)660 except StopIteration:661 num_active -= 1662 if not num_active:663 return664 iterators[i] = repeat(fillvalue)665 value = fillvalue666 values.append(value)667 yield tuple(values)668```669670Если один из итерируемых объектов потенциально бесконечен, то функция `zip_longest()` должна быть обёрнута чем-то, что ограничивает количество вызовов (например, [`islice()`](https://python-all.ru/3.15/library/itertools.html#itertools.islice) или [`takewhile()`](https://python-all.ru/3.15/library/itertools.html#itertools.takewhile)).671672## Рецепты itertools673674В этом разделе представлены рецепты для создания расширенного набора инструментов с использованием существующих itertools в качестве строительных блоков.675676Основная цель рецептов itertools – образовательная. Рецепты демонстрируют различные способы мышления об отдельных инструментах – например, что `chain.from_iterable` связано с концепцией уплощения. Рецепты также дают идеи о том, как инструменты можно комбинировать – например, как `starmap()` и `repeat()` могут работать вместе. Рецепты также показывают шаблоны использования itertools с модулями [`operator`](https://python-all.ru/3.15/library/operator.html#module-operator) и [`collections`](https://python-all.ru/3.15/library/collections.html#module-collections), а также со встроенными itertools, такими как `map()`, `filter()`, `reversed()` и `enumerate()`.677678Второстепенная цель рецептов – служить инкубатором. `accumulate()`, `compress()` и `pairwise()` изначально были рецептами. В настоящее время рецепты `sliding_window()`, `derangements()` и `sieve()` тестируются, чтобы проверить, оправдают ли они себя.679680Практически все эти и многие другие рецепты можно установить из проекта [more-itertools](https://python-all.ru/3.15/library/itertools.html), доступного на Python Package Index:681682```python683python -m pip install more-itertools684```685686Многие рецепты обеспечивают такую же высокую производительность, как и базовый набор инструментов. Превосходная производительность по памяти достигается за счёт обработки элементов по одному, а не загрузки всего итерируемого объекта в память сразу. Объём кода сохраняется небольшим за счёт связывания инструментов в [функциональном стиле](https://python-all.ru/3.15/library/itertools.html). Высокая скорость сохраняется благодаря предпочтению «векторизованных» строительных блоков перед использованием циклов for и [генераторов](https://python-all.ru/3.15/glossary.html#term-generator), которые влекут накладные расходы интерпретатора.687688```python689from itertools import (accumulate, batched, chain, combinations, compress,690 count, cycle, filterfalse, groupby, islice, permutations, product,691 repeat, starmap, tee, zip_longest)692from collections import Counter, deque693from contextlib import suppress694from functools import reduce695from heapq import heappush, heappushpop, heappush_max, heappushpop_max696from math import comb, isqrt, prod, sumprod697from operator import getitem, is_not, itemgetter, mul, neg, truediv698699# ==== Базовые однострочники ====700701def take(n, iterable):702 "Return first n items of the iterable as a list."703 return list(islice(iterable, n))704705def prepend(value, iterable):706 "Prepend a single value in front of an iterable."707 # prepend(1, [2, 3, 4]) → 1 2 3 4708 return chain([value], iterable)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))) <= 1760761# ==== Конвейеры данных ====762763def unique_justseen(iterable, key=None):764 "Yield unique elements, preserving order. Remember only the element just seen."765 # unique_justseen('AAAABBBCCDAABBB') → A B C D A B766 # unique_justseen('ABBcCAD', str.casefold) → A B c A D767 if key is None:768 return map(itemgetter(0), groupby(iterable))769 return map(next, map(itemgetter(1), groupby(iterable, key)))770771def unique_everseen(iterable, key=None):772 "Yield unique elements, preserving order. Remember all elements ever seen."773 # unique_everseen('AAAABBBCCDAABBB') → A B C D774 # unique_everseen('ABBcCAD', str.casefold) → A B c D775 seen = set()776 if key is None:777 for element in filterfalse(seen.__contains__, iterable):778 seen.add(element)779 yield element780 else:781 for element in iterable:782 k = key(element)783 if k not in seen:784 seen.add(k)785 yield element786787def unique(iterable, key=None, reverse=False):788 "Yield unique elements in sorted order. Supports unhashable inputs."789 # unique([[1, 2], [3, 4], [1, 2]]) → [1, 2] [3, 4]790 sequenced = sorted(iterable, key=key, reverse=reverse)791 return unique_justseen(sequenced, key=key)792793def sliding_window(iterable, n):794 "Collect data into overlapping fixed-length chunks or blocks."795 # sliding_window('ABCDEFG', 3) → ABC BCD CDE DEF EFG796 iterator = iter(iterable)797 window = deque(islice(iterator, n - 1), maxlen=n)798 for x in iterator:799 window.append(x)800 yield tuple(window)801802def grouper(iterable, n, *, incomplete='fill', fillvalue=None):803 "Collect data into non-overlapping fixed-length chunks or blocks."804 # grouper('ABCDEFG', 3, fillvalue='x') → ABC DEF Gxx805 # grouper('ABCDEFG', 3, incomplete='strict') → ABC DEF ValueError806 # grouper('ABCDEFG', 3, incomplete='ignore') → ABC DEF807 iterators = [iter(iterable)] * n808 match incomplete:809 case 'fill':810 return zip_longest(*iterators, fillvalue=fillvalue)811 case 'strict':812 return zip(*iterators, strict=True)813 case 'ignore':814 return zip(*iterators)815 case _:816 raise ValueError('Expected fill, strict, or ignore')817818def roundrobin(*iterables):819 "Visit input iterables in a cycle until each is exhausted."820 # roundrobin('ABC', 'D', 'EF') → A D E B F C821 # Алгоритм Джорджа Саккиса822 iterators = map(iter, iterables)823 for num_active in range(len(iterables), 0, -1):824 iterators = cycle(islice(iterators, num_active))825 yield from map(next, iterators)826827def subslices(seq):828 "Return all contiguous non-empty subslices of a sequence."829 # subslices('ABCD') → A AB ABC ABCD B BC BCD C CD D830 slices = starmap(slice, combinations(range(len(seq) + 1), 2))831 return map(getitem, repeat(seq), slices)832833def derangements(iterable, r=None):834 "Produce r length permutations without fixed points."835 # derangements('ABCD') → BADC BCDA BDAC CADB CDAB CDBA DABC DCAB DCBA836 # Алгоритм Стефана Похманна837 seq = tuple(iterable)838 pos = tuple(range(len(seq)))839 have_moved = map(map, repeat(is_not), repeat(pos), permutations(pos, r=r))840 valid_derangements = map(all, have_moved)841 return compress(permutations(seq, r=r), valid_derangements)842843def iter_index(iterable, value, start=0, stop=None):844 "Return indices where a value occurs in a sequence or iterable."845 # iter_index('AABCADEAF', 'A') → 0 1 4 7846 seq_index = getattr(iterable, 'index', None)847 if seq_index is None:848 iterator = islice(iterable, start, stop)849 for i, element in enumerate(iterator, start):850 if element is value or element == value:851 yield i852 else:853 stop = len(iterable) if stop is None else stop854 i = start855 with suppress(ValueError):856 while True:857 yield (i := seq_index(value, i, stop))858 i += 1859860def iter_except(function, exception, first=None):861 "Convert a call-until-exception interface to an iterator interface."862 # iter_except(d.popitem, KeyError) → неблокирующий итератор словаря863 with suppress(exception):864 if first is not None:865 yield first()866 while True:867 yield function()868869# ==== Математические операции ====870871def multinomial(*counts):872 "Number of distinct arrangements of a multiset."873 # Counter('abracadabra').values() → 5 2 2 1 1874 # multinomial(5, 2, 2, 1, 1) → 83160875 return prod(map(comb, accumulate(counts), counts))876877def powerset(iterable):878 "Subsequences of the iterable from shortest to longest."879 # powerset([1,2,3]) → () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)880 s = list(iterable)881 return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))882883def sum_of_squares(iterable):884 "Add up the squares of the input values."885 # sum_of_squares([10, 20, 30]) → 1400886 return sumprod(*tee(iterable))887888# ==== Операции с матрицами ====889890def reshape(matrix, columns):891 "Reshape a 2-D matrix to have a given number of columns."892 # reshape([(0, 1), (2, 3), (4, 5)], 3) → (0, 1, 2) (3, 4, 5)893 return batched(chain.from_iterable(matrix), columns, strict=True)894895def transpose(matrix):896 "Swap the rows and columns of a 2-D matrix."897 # transpose([(1, 2, 3), (11, 22, 33)]) → (1, 11) (2, 22) (3, 33)898 return zip(*matrix, strict=True)899900def matmul(m1, m2):901 "Multiply two matrices."902 # matmul([(7, 5), (3, 5)], [(2, 5), (7, 9)]) → (49, 80) (41, 60)903 n = len(m2[0])904 return batched(starmap(sumprod, product(m1, transpose(m2))), n)905906# ==== Арифметика многочленов ====907908def convolve(signal, kernel):909 """Дискретная линейная свёртка двух итерируемых объектов.910 Эквивалентно умножению многочленов.911912 Свёртки математически коммутативны; однако входные данные913 вычисляются по-разному. Сигнал потребляется лениво и может быть914 бесконечным. Ядро полностью потребляется до начала вычислений.915916 Статья: https://betterexplained.com/articles/intuitive-convolution/917 Видео: https://www.youtube.com/watch?v=KuXjwB4LzSA918 """919 # convolve([1, -1, -20], [1, -3]) → 1 -4 -17 60920 # convolve(data, [0.25, 0.25, 0.25, 0.25]) → Скользящее среднее (размытие)921 # convolve(data, [1/2, 0, -1/2]) → Оценка первой производной922 # convolve(data, [1, -2, 1]) → Оценка второй производной923 kernel = tuple(kernel)[::-1]924 n = len(kernel)925 padded_signal = chain(repeat(0, n-1), signal, repeat(0, n-1))926 windowed_signal = sliding_window(padded_signal, n)927 return map(sumprod, repeat(kernel), windowed_signal)928929def polynomial_from_roots(roots):930 """Вычисляет коэффициенты многочлена по его корням.931932 (x - 5) (x + 4) (x - 3) раскрывается в: x³ -4x² -17x + 60933 """934 # polynomial_from_roots([5, -4, 3]) → [1, -4, -17, 60]935 factors = zip(repeat(1), map(neg, roots))936 return list(reduce(convolve, factors, [1]))937938def polynomial_eval(coefficients, x):939 """Вычисляет значение многочлена в заданной точке.940941 Вычисляет с лучшей численной устойчивостью, чем метод Горнера.942 """943 # Вычислить x³ -4x² -17x + 60 при x = 5944 # polynomial_eval([1, -4, -17, 60], x=5) → 0945 n = len(coefficients)946 if not n:947 return type(x)(0)948 powers = map(pow, repeat(x), reversed(range(n)))949 return sumprod(coefficients, powers)950951def polynomial_derivative(coefficients):952 """Вычисляет первую производную многочлена.953954 f(x) = x³ -4x² -17x + 60955 f'(x) = 3x² -8x -17956 """957 # polynomial_derivative([1, -4, -17, 60]) → [3, -8, -17]958 n = len(coefficients)959 powers = reversed(range(1, n))960 return list(map(mul, coefficients, powers))961962# ==== Теория чисел ====963964def sieve(n):965 "Primes less than n."966 # sieve(30) → 2 3 5 7 11 13 17 19 23 29967 if n > 2:968 yield 2969 data = bytearray((0, 1)) * (n // 2)970 for p in iter_index(data, 1, start=3, stop=isqrt(n) + 1):971 data[p*p : n : p+p] = bytes(len(range(p*p, n, p+p)))972 yield from iter_index(data, 1, start=3)973974def factor(n):975 "Prime factors of n."976 # factor(99) → 3 3 11977 # factor(1_000_000_000_000_007) → 47 59 360620266859978 # factor(1_000_000_000_000_403) → 1000000000000403979 for prime in sieve(isqrt(n) + 1):980 while not n % prime:981 yield prime982 n //= prime983 if n == 1:984 return985 if n > 1:986 yield n987988def is_prime(n):989 "Return True if n is prime."990 # is_prime(1_000_000_000_000_403) → True991 return n > 1 and next(factor(n)) == n992993def totient(n):994 "Count of natural numbers up to n that are coprime to n."995 # https://mathworld.wolfram.com/TotientFunction.html996 # totient(12) → 4 потому что len([1, 5, 7, 11]) == 4997 for prime in set(factor(n)):998 n -= n // prime999 return n10001001# ==== Скользящие статистики ====10021003def running_mean(iterable):1004 "Average of values seen so far."1005 # running_mean([37, 33, 38, 28]) → 37 35 36 341006 return map(truediv, accumulate(iterable), count(1))10071008def running_min(iterable):1009 "Smallest of values seen so far."1010 # running_min([37, 33, 38, 28]) → 37 33 33 281011 return accumulate(iterable, func=min)10121013def running_max(iterable):1014 "Largest of values seen so far."1015 # running_max([37, 33, 38, 28]) → 37 37 38 381016 return accumulate(iterable, func=max)10171018def running_median(iterable):1019 "Median of values seen so far."1020 # running_median([37, 33, 38, 28]) → 37 35 37 351021 read = iter(iterable).__next__1022 lo = [] # максимальная куча1023 hi = [] # мин-куча того же размера, что и lo, или на единицу меньше1024 with suppress(StopIteration):1025 while True:1026 heappush_max(lo, heappushpop(hi, read()))1027 yield lo[0]1028 heappush(hi, heappushpop_max(lo, read()))1029 yield (lo[0] + hi[0]) / 210301031def running_statistics(iterable):1032 "Aggregate statistics for values seen so far."1033 # Создать кортежи: (size, minimum, median, maximum, mean)1034 t0, t1, t2, t3 = tee(iterable, 4)1035 return zip(1036 count(1),1037 running_min(t0),1038 running_median(t1),1039 running_max(t2),1040 running_mean(t3),1041 )1042```1043