Документация Python неофициальный перевод

itertools.md

985 строк · 53.6 КБ · обычная страница · сырой текст · скачать

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