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

itertools.md

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

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