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

itertools.md

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

1> **Источник:** https://python-all.ru/3.7/library/itertools.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# [`itertools`](https://python-all.ru/3.7/library/itertools.html#module-itertools) – Функции, создающие итераторы для эффективного перебора89---1011Этот модуль реализует ряд строительных блоков [итераторов](https://python-all.ru/3.7/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.7/library/functions.html#map) и [`count()`](https://python-all.ru/3.7/library/itertools.html#itertools.count) для получения `map(f, count())`.1617Эти инструменты и их встроенные аналоги также хорошо работают с высокоскоростными функциями из модуля [`operator`](https://python-all.ru/3.7/library/operator.html#module-operator). Например, оператор умножения можно применить к двум векторам, чтобы получить эффективное скалярное произведение: `sum(map(operator.mul, vector1, vector2))`.1819**Бесконечные итераторы:**2021| Итератор | Аргументы | Результаты | Пример |22| --- | --- | --- | --- |23| [`count()`](https://python-all.ru/3.7/library/itertools.html#itertools.count) | start, \[step\] | start, start+step, start+2\*step, … | `count(10) --> 10 11 12 13 14 ...` |24| [`cycle()`](https://python-all.ru/3.7/library/itertools.html#itertools.cycle) | p | p0, p1, … plast, p0, p1, … | `cycle('ABCD') --> A B C D A B C D ...` |25| [`repeat()`](https://python-all.ru/3.7/library/itertools.html#itertools.repeat) | elem \[,n\] | elem, elem, elem, … бесконечно или до n раз | `repeat(10, 3) --> 10 10 10` |2627**Итераторы, завершающиеся по кратчайшей входной последовательности:**2829| Итератор | Аргументы | Результаты | Пример |30| --- | --- | --- | --- |31| [`accumulate()`](https://python-all.ru/3.7/library/itertools.html#itertools.accumulate) | p \[,func\] | p0, p0+p1, p0+p1+p2, … | `accumulate([1,2,3,4,5]) --> 1 3 6 10 15` |32| [`chain()`](https://python-all.ru/3.7/library/itertools.html#itertools.chain) | p, q, … | p0, p1, … plast, q0, q1, … | `chain('ABC', 'DEF') --> A B C D E F` |33| [`chain.from_iterable()`](https://python-all.ru/3.7/library/itertools.html#itertools.chain.from_iterable) | итерируемый объект | p0, p1, … plast, q0, q1, … | `chain.from_iterable(['ABC', 'DEF']) --> A B C D E F` |34| [`compress()`](https://python-all.ru/3.7/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` |35| [`dropwhile()`](https://python-all.ru/3.7/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` |36| [`filterfalse()`](https://python-all.ru/3.7/library/itertools.html#itertools.filterfalse) | pred, seq | элементы seq, для которых pred(elem) ложно | `filterfalse(lambda x: x%2, range(10)) --> 0 2 4 6 8` |37| [`groupby()`](https://python-all.ru/3.7/library/itertools.html#itertools.groupby) | iterable\[, key\] | подитераторы, сгруппированные по значению key(v) |  |38| [`islice()`](https://python-all.ru/3.7/library/itertools.html#itertools.islice) | seq, \[start,\] stop \[, step\] | элементы из seq\[start:stop:step\] | `islice('ABCDEFG', 2, None) --> C D E F G` |39| [`starmap()`](https://python-all.ru/3.7/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.7/library/itertools.html#itertools.takewhile) | pred, seq | seq\[0\], seq\[1\], пока pred не вернёт ложь | `takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4` |41| [`tee()`](https://python-all.ru/3.7/library/itertools.html#itertools.tee) | it, n | it1, it2, … itn разделяет один итератор на n |  |42| [`zip_longest()`](https://python-all.ru/3.7/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.7/library/itertools.html#itertools.product) | p, q, … \[repeat=1\] | декартово произведение, эквивалентно вложенному циклу for |49| [`permutations()`](https://python-all.ru/3.7/library/itertools.html#itertools.permutations) | p\[, r\] | кортежи длиной r, все возможные перестановки, без повторяющихся элементов |50| [`combinations()`](https://python-all.ru/3.7/library/itertools.html#itertools.combinations) | p, r | кортежи длиной r, в отсортированном порядке, без повторяющихся элементов |51| [`combinations_with_replacement()`](https://python-all.ru/3.7/library/itertools.html#itertools.combinations_with_replacement) | p, r | кортежи длиной r, в отсортированном порядке, с повторяющимися элементами |52| `product('ABCD', repeat=2)` |  | `AA AB AC AD BA BB BC BD CA CB CC CD DA DB DC DD` |53| `permutations('ABCD', 2)` |  | `AB AC AD BA BC BD CA CB CD DA DB DC` |54| `combinations('ABCD', 2)` |  | `AB AC AD BC BD CD` |55| `combinations_with_replacement('ABCD', 2)` |  | `AA AB AC AD BB BC BD CC CD DD` |5657## Функции итераторных инструментов5859Следующие функции модуля создают и возвращают итераторы. Некоторые из них порождают потоки бесконечной длины, поэтому обращаться к ним следует только с помощью функций или циклов, которые обрывают поток.6061#### `itertools.accumulate(iterable[, func])`6263Создаёт итератор, возвращающий накопленные суммы или накопленные результаты других бинарных функций (задаваемых необязательным аргументом *func*). Если *func* указана, это должна быть функция двух аргументов. Элементы входного *iterable* могут быть любого типа, который может быть принят в качестве аргумента *func*. (Например, при стандартной операции сложения элементы могут быть любого складываемого типа, включая [`Decimal`](https://python-all.ru/3.7/library/decimal.html#decimal.Decimal) или [`Fraction`](https://python-all.ru/3.7/library/fractions.html#fractions.Fraction).) Если входной итератор пуст, выходной итератор также будет пуст.6465Примерно эквивалентно:6667```python68def accumulate(iterable, func=operator.add):69    'Return running totals'70    # accumulate([1,2,3,4,5]) --> 1 3 6 10 1571    # accumulate([1,2,3,4,5], operator.mul) --> 1 2 6 24 12072    it = iter(iterable)73    try:74        total = next(it)75    except StopIteration:76        return77    yield total78    for element in it:79        total = func(total, element)80        yield total81```8283У аргумента *func* есть несколько применений. Его можно установить в [`min()`](https://python-all.ru/3.7/library/functions.html#min) для текущего минимума, [`max()`](https://python-all.ru/3.7/library/functions.html#max) для текущего максимума или [`operator.mul()`](https://python-all.ru/3.7/library/operator.html#operator.mul) для текущего произведения. Таблицы амортизации можно построить, накапливая проценты и применяя платежи. [Рекуррентные соотношения](https://python-all.ru/3.7/library/itertools.html) первого порядка можно смоделировать, передав начальное значение в итерируемом объекте и используя только накопленную сумму в аргументе *func*:8485```python86>>> data = [3, 4, 6, 2, 1, 9, 0, 7, 5, 8]87>>> list(accumulate(data, operator.mul))     # текущее произведение88[3, 12, 72, 144, 144, 1296, 0, 0, 0, 0]89>>> list(accumulate(data, max))              # текущий максимум90[3, 4, 6, 6, 6, 9, 9, 9, 9, 9]9192# Amortize a 5% loan of 1000 with 4 annual payments of 9093>>> cashflows = [1000, -90, -90, -90, -90]94>>> list(accumulate(cashflows, lambda bal, pmt: bal*1.05 + pmt))95[1000, 960.0, 918.0, 873.9000000000001, 827.5950000000001]9697# Chaotic recurrence relation https://en.wikipedia.org/wiki/Logistic_map98>>> logistic_map = lambda x, _:  r * x * (1 - x)99>>> r = 3.8100>>> x0 = 0.4101>>> inputs = repeat(x0, 36)     # используется только начальное значение102>>> [format(x, '.2f') for x in accumulate(inputs, logistic_map)]103['0.40', '0.91', '0.30', '0.81', '0.60', '0.92', '0.29', '0.79', '0.63',104 '0.88', '0.39', '0.90', '0.33', '0.84', '0.52', '0.95', '0.18', '0.57',105 '0.93', '0.25', '0.71', '0.79', '0.63', '0.88', '0.39', '0.91', '0.32',106 '0.83', '0.54', '0.95', '0.20', '0.60', '0.91', '0.30', '0.80', '0.60']107```108109См. [`functools.reduce()`](https://python-all.ru/3.7/library/functools.html#functools.reduce) – похожая функция, возвращающая только итоговое накопленное значение.110111Новое в версии 3.2.112113Изменено в версии 3.3: Добавлен необязательный параметр *func*.114115#### `itertools.chain(*iterables)`116117Создаёт итератор, который возвращает элементы из первого итерируемого объекта, пока он не будет исчерпан, затем переходит к следующему, пока все итерируемые объекты не будут исчерпаны. Используется для объединения последовательностей в одну. Приблизительный эквивалент:118119```python120def chain(*iterables):121    # chain('ABC', 'DEF') --> A B C D E F122    for it in iterables:123        for element in it:124            yield element125```126127#### `classmethod chain.from_iterable(iterable)`128129Альтернативный конструктор для [`chain()`](https://python-all.ru/3.7/library/itertools.html#itertools.chain). Получает цепочку входных данных из одного аргумента iterable, который вычисляется лениво. Примерная реализация:130131```python132def from_iterable(iterables):133    # chain.from_iterable(['ABC', 'DEF']) --> A B C D E F134    for it in iterables:135        for element in it:136            yield element137```138139#### `itertools.combinations(iterable, r)`140141Возвращает подпоследовательности элементов длины *r* из входного *iterable*.142143Комбинации выдаются в лексикографическом порядке сортировки. Поэтому, если входной *iterable* отсортирован, кортежи комбинаций будут создаваться в отсортированном порядке.144145Элементы считаются уникальными на основе их позиции, а не значения. Поэтому если входные элементы уникальны, то в каждой комбинации не будет повторяющихся значений.146147Примерно эквивалентно:148149```python150def combinations(iterable, r):151    # combinations('ABCD', 2) --> AB AC AD BC BD CD152    # combinations(range(4), 3) --> 012 013 023 123153    pool = tuple(iterable)154    n = len(pool)155    if r > n:156        return157    indices = list(range(r))158    yield tuple(pool[i] for i in indices)159    while True:160        for i in reversed(range(r)):161            if indices[i] != i + n - r:162                break163        else:164            return165        indices[i] += 1166        for j in range(i+1, r):167            indices[j] = indices[j-1] + 1168        yield tuple(pool[i] for i in indices)169```170171Код для [`combinations()`](https://python-all.ru/3.7/library/itertools.html#itertools.combinations) можно также выразить как подпоследовательность [`permutations()`](https://python-all.ru/3.7/library/itertools.html#itertools.permutations) после фильтрации записей, где элементы не находятся в отсортированном порядке (согласно их позиции во входном пуле):172173```python174def combinations(iterable, r):175    pool = tuple(iterable)176    n = len(pool)177    for indices in permutations(range(n), r):178        if sorted(indices) == list(indices):179            yield tuple(pool[i] for i in indices)180```181182Количество возвращаемых элементов равно `n! / r! / (n-r)!`, когда `0 <= r <= n`, или нулю, когда `r > n`.183184#### `itertools.combinations_with_replacement(iterable, r)`185186Возвращает подпоследовательности элементов длины *r* из входного *iterable*, допуская повторение отдельных элементов.187188Комбинации выдаются в лексикографическом порядке. Таким образом, если входной *итерируемый объект* отсортирован, кортежи комбинаций будут созданы в отсортированном порядке.189190Элементы считаются уникальными по их позиции, а не по значению. Поэтому если входные элементы уникальны, сгенерированные комбинации также будут уникальны.191192Примерно эквивалентно:193194```python195def combinations_with_replacement(iterable, r):196    # combinations_with_replacement('ABC', 2) --> AA AB AC BB BC CC197    pool = tuple(iterable)198    n = len(pool)199    if not n and r:200        return201    indices = [0] * r202    yield tuple(pool[i] for i in indices)203    while True:204        for i in reversed(range(r)):205            if indices[i] != n - 1:206                break207        else:208            return209        indices[i:] = [indices[i] + 1] * (r - i)210        yield tuple(pool[i] for i in indices)211```212213Код для [`combinations_with_replacement()`](https://python-all.ru/3.7/library/itertools.html#itertools.combinations_with_replacement) можно также выразить как подпоследовательность [`product()`](https://python-all.ru/3.7/library/itertools.html#itertools.product) после фильтрации записей, где элементы не находятся в отсортированном порядке (согласно их позиции во входном пуле):214215```python216def combinations_with_replacement(iterable, r):217    pool = tuple(iterable)218    n = len(pool)219    for indices in product(range(n), repeat=r):220        if sorted(indices) == list(indices):221            yield tuple(pool[i] for i in indices)222```223224Количество возвращаемых элементов равно `(n+r-1)! / r! / (n-1)!`, когда `n > 0`.225226Новое в версии 3.1.227228#### `itertools.compress(data, selectors)`229230Создаёт итератор, который фильтрует элементы из *data*, возвращая только те, для которых в *selectors* есть соответствующий элемент, вычисляемый как `True`. Останавливается, когда исчерпан либо итерабельный объект *data*, либо *selectors*. Примерно эквивалентен:231232```python233def compress(data, selectors):234    # compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F235    return (d for d, s in zip(data, selectors) if s)236```237238Новое в версии 3.1.239240#### `itertools.count(start=0, step=1)`241242Создаёт итератор, возвращающий равномерно распределённые значения, начиная с числа *start*. Часто используется как аргумент для [`map()`](https://python-all.ru/3.7/library/functions.html#map) для генерации последовательных точек данных. Также используется с [`zip()`](https://python-all.ru/3.7/library/functions.html#zip) для добавления порядковых номеров. Примерно эквивалентен:243244```python245def count(start=0, step=1):246    # count(10) --> 10 11 12 13 14 ...247    # count(2.5, 0.5) -> 2.5 3.0 3.5 ...248    n = start249    while True:250        yield n251        n += step252```253254При подсчёте с числами с плавающей запятой иногда можно добиться лучшей точности, заменив код на мультипликативный, например: `(start + step * i for i in count())`.255256Изменено в версии 3.1: Добавлен аргумент *step* и разрешены нецелые аргументы.257258#### `itertools.cycle(iterable)`259260Создаёт итератор, возвращающий элементы из итерабельного объекта и сохраняющий копию каждого. Когда итерабельный объект исчерпан, возвращает элементы из сохранённой копии. Повторяется бесконечно. Примерно эквивалентен:261262```python263def cycle(iterable):264    # cycle('ABCD') --> A B C D A B C D A B C D ...265    saved = []266    for element in iterable:267        yield element268        saved.append(element)269    while saved:270        for element in saved:271              yield element272```273274Примечание: этот элемент набора инструментов может потребовать значительного дополнительного хранилища (в зависимости от длины итерабельного объекта).275276#### `itertools.dropwhile(predicate, iterable)`277278Создаёт итератор, который отбрасывает элементы из итерабельного объекта, пока предикат истинен; после этого возвращает каждый элемент. Примечание: итератор не выдаёт *никакого* вывода, пока предикат впервые не станет ложным, поэтому время запуска может быть большим. Примерно эквивалентен:279280```python281def dropwhile(predicate, iterable):282    # dropwhile(lambda x: x<5, [1,4,6,4,1]) --> 6 4 1283    iterable = iter(iterable)284    for x in iterable:285        if not predicate(x):286            yield x287            break288    for x in iterable:289        yield x290```291292#### `itertools.filterfalse(predicate, iterable)`293294Создаёт итератор, который фильтрует элементы из итерируемого объекта, возвращая только те, для которых предикат равен `False`. Если *предикат* равен `None`, возвращает элементы, которые являются ложными. Примерно эквивалентно:295296```python297def filterfalse(predicate, iterable):298    # filterfalse(lambda x: x%2, range(10)) --> 0 2 4 6 8299    if predicate is None:300        predicate = bool301    for x in iterable:302        if not predicate(x):303            yield x304```305306#### `itertools.groupby(iterable, key=None)`307308Make 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.309310Работа [`groupby()`](https://python-all.ru/3.7/library/itertools.html#itertools.groupby) аналогична фильтру `uniq` в Unix. Она создает разрыв или новую группу каждый раз, когда изменяется значение ключевой функции (поэтому обычно необходимо отсортировать данные с помощью той же ключевой функции). Такое поведение отличается от SQL GROUP BY, которая объединяет общие элементы независимо от порядка их ввода.311312Возвращаемая группа сама является итератором, который использует общий исходный итерируемый объект с [`groupby()`](https://python-all.ru/3.7/library/itertools.html#itertools.groupby). Поскольку источник общий, при продвижении объекта [`groupby()`](https://python-all.ru/3.7/library/itertools.html#itertools.groupby) предыдущая группа перестает быть видимой. Поэтому, если эти данные понадобятся позже, их следует сохранить в виде списка:313314```python315groups = []316uniquekeys = []317data = sorted(data, key=keyfunc)318for k, g in groupby(data, keyfunc):319    groups.append(list(g))      # Сохранить групповой итератор как список320    uniquekeys.append(k)321```322323[`groupby()`](https://python-all.ru/3.7/library/itertools.html#itertools.groupby) примерно эквивалентно:324325```python326class groupby:327    # [k for k, g in groupby('AAAABBBCCDAABBB')] --> A B C D A B328    # [list(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D329    def __init__(self, iterable, key=None):330        if key is None:331            key = lambda x: x332        self.keyfunc = key333        self.it = iter(iterable)334        self.tgtkey = self.currkey = self.currvalue = object()335    def __iter__(self):336        return self337    def __next__(self):338        self.id = object()339        while self.currkey == self.tgtkey:340            self.currvalue = next(self.it)    # Выход при StopIteration341            self.currkey = self.keyfunc(self.currvalue)342        self.tgtkey = self.currkey343        return (self.currkey, self._grouper(self.tgtkey, self.id))344    def _grouper(self, tgtkey, id):345        while self.id is id and self.currkey == tgtkey:346            yield self.currvalue347            try:348                self.currvalue = next(self.it)349            except StopIteration:350                return351            self.currkey = self.keyfunc(self.currvalue)352```353354#### `itertools.islice(iterable, stop)`355356#### `itertools.islice(iterable, start, stop[, step])`357358Создаёт итератор, который возвращает выбранные элементы из итерируемого объекта. Если *start* не равен нулю, то элементы из итерируемого объекта пропускаются до достижения start. Затем элементы возвращаются последовательно, если только *step* не установлен больше единицы, что приводит к пропуску элементов. Если *stop* равен `None`, то итерация продолжается до тех пор, пока итератор не будет исчерпан, если вообще; в противном случае она останавливается на указанной позиции. В отличие от обычной срезки, [`islice()`](https://python-all.ru/3.7/library/itertools.html#itertools.islice) не поддерживает отрицательные значения для *start*, *stop* или *step*. Может использоваться для извлечения связанных полей из данных, где внутренняя структура была уплощена (например, многострочный отчёт может содержать поле имени на каждой третьей строке). Примерно эквивалентно:359360```python361def islice(iterable, *args):362    # islice('ABCDEFG', 2) --> A B363    # islice('ABCDEFG', 2, 4) --> C D364    # islice('ABCDEFG', 2, None) --> C D E F G365    # islice('ABCDEFG', 0, None, 2) --> A C E G366    s = slice(*args)367    start, stop, step = s.start or 0, s.stop or sys.maxsize, s.step or 1368    it = iter(range(start, stop, step))369    try:370        nexti = next(it)371    except StopIteration:372        # Потребляет *iterable* до позиции *start*.373        for i, element in zip(range(start), iterable):374            pass375        return376    try:377        for i, element in enumerate(iterable):378            if i == nexti:379                yield element380                nexti = next(it)381    except StopIteration:382        # Потребляет до *stop*.383        for i, element in zip(range(i + 1, stop), iterable):384            pass385```386387Если *start* равен `None`, то итерация начинается с нуля. Если *step* равен `None`, то шаг по умолчанию равен единице.388389#### `itertools.permutations(iterable, r=None)`390391Возвращает последовательные перестановки длины *r* элементов из *iterable*.392393Если *r* не указан или равен `None`, то *r* по умолчанию равен длине *iterable* и генерируются все возможные перестановки полной длины.394395Перестановки выдаются в лексикографическом порядке. Таким образом, если входной *итерируемый объект* отсортирован, кортежи перестановок будут созданы в отсортированном порядке.396397Элементы считаются уникальными на основе их позиции, а не значения. Поэтому если входные элементы уникальны, то в каждой перестановке не будет повторяющихся значений.398399Примерно эквивалентно:400401```python402def permutations(iterable, r=None):403    # permutations('ABCD', 2) --> AB AC AD BA BC BD CA CB CD DA DB DC404    # permutations(range(3)) --> 012 021 102 120 201 210405    pool = tuple(iterable)406    n = len(pool)407    r = n if r is None else r408    if r > n:409        return410    indices = list(range(n))411    cycles = list(range(n, n-r, -1))412    yield tuple(pool[i] for i in indices[:r])413    while n:414        for i in reversed(range(r)):415            cycles[i] -= 1416            if cycles[i] == 0:417                indices[i:] = indices[i+1:] + indices[i:i+1]418                cycles[i] = n - i419            else:420                j = cycles[i]421                indices[i], indices[-j] = indices[-j], indices[i]422                yield tuple(pool[i] for i in indices[:r])423                break424        else:425            return426```427428Код для [`permutations()`](https://python-all.ru/3.7/library/itertools.html#itertools.permutations) также можно выразить как подпоследовательность [`product()`](https://python-all.ru/3.7/library/itertools.html#itertools.product), отфильтрованную для исключения записей с повторяющимися элементами (тех, которые находятся на одной и той же позиции во входном пуле):429430```python431def permutations(iterable, r=None):432    pool = tuple(iterable)433    n = len(pool)434    r = n if r is None else r435    for indices in product(range(n), repeat=r):436        if len(set(indices)) == r:437            yield tuple(pool[i] for i in indices)438```439440Количество возвращаемых элементов равно `n! / (n-r)!`, когда `0 <= r <= n`, или нулю, когда `r > n`.441442#### `itertools.product(*iterables, repeat=1)`443444Декартово произведение входных итерируемых объектов.445446Примерно эквивалентно вложенным циклам for в генераторном выражении. Например, `product(A, B)` возвращает то же, что и `((x,y) for x in A for y in B)`.447448Вложенные циклы работают как одометр: самый правый элемент увеличивается на каждой итерации. Этот шаблон создает лексикографический порядок, так что если входные итерируемые объекты отсортированы, кортежи произведения выдаются в отсортированном порядке.449450Чтобы вычислить произведение итерируемого объекта на самого себя, укажите количество повторений с помощью необязательного именованного аргумента *repeat*. Например, `product(A, repeat=4)` эквивалентно `product(A, A, A, A)`.451452Эта функция примерно эквивалентна следующему коду, за исключением того, что реальная реализация не накапливает промежуточные результаты в памяти:453454```python455def product(*args, repeat=1):456    # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy457    # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111458    pools = [tuple(pool) for pool in args] * repeat459    result = [[]]460    for pool in pools:461        result = [x+[y] for x in result for y in pool]462    for prod in result:463        yield tuple(prod)464```465466#### `itertools.repeat(object[, times])`467468Создаёт итератор, который снова и снова возвращает *object*. Выполняется бесконечно, если не указан аргумент *times*. Используется как аргумент [`map()`](https://python-all.ru/3.7/library/functions.html#map) для инвариантных параметров вызываемой функции. Также используется с [`zip()`](https://python-all.ru/3.7/library/functions.html#zip) для создания инвариантной части кортежной записи.469470Примерно эквивалентно:471472```python473def repeat(object, times=None):474    # repeat(10, 3) --> 10 10 10475    if times is None:476        while True:477            yield object478    else:479        for i in range(times):480            yield object481```482483Обычное применение *repeat* – передача потока постоянных значений в *map* или *zip*:484485```python486>>> list(map(pow, range(10), repeat(2)))487[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]488```489490#### `itertools.starmap(function, iterable)`491492Создаёт итератор, который вычисляет функцию, используя аргументы, полученные из итерируемого объекта. Используется вместо [`map()`](https://python-all.ru/3.7/library/functions.html#map), когда параметры аргументов уже сгруппированы в кортежи из одного итерируемого объекта (данные были «предварительно сжаты»). Разница между [`map()`](https://python-all.ru/3.7/library/functions.html#map) и [`starmap()`](https://python-all.ru/3.7/library/itertools.html#itertools.starmap) параллельна различию между `function(a,b)` и `function(*c)`. Примерно эквивалентно:493494```python495def starmap(function, iterable):496    # starmap(pow, [(2,5), (3,2), (10,3)]) --> 32 9 1000497    for args in iterable:498        yield function(*args)499```500501#### `itertools.takewhile(predicate, iterable)`502503Создаёт итератор, возвращающий элементы из итерируемого объекта, пока предикат истинен. Приблизительно эквивалентно:504505```python506def takewhile(predicate, iterable):507    # takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4508    for x in iterable:509        if predicate(x):510            yield x511        else:512            break513```514515#### `itertools.tee(iterable, n=2)`516517Возвращает *n* независимых итераторов из одного итерируемого объекта.518519Следующий код на Python помогает объяснить, что делает *tee* (хотя реальная реализация более сложна и использует только одну базовую очередь FIFO).520521Примерно эквивалентно:522523```python524def tee(iterable, n=2):525    it = iter(iterable)526    deques = [collections.deque() for i in range(n)]527    def gen(mydeque):528        while True:529            if not mydeque:             # когда локальная deque пуста530                try:531                    newval = next(it)   # извлечь новое значение и532                except StopIteration:533                    return534                for d in deques:        # загрузить его во все двусторонние очереди535                    d.append(newval)536            yield mydeque.popleft()537    return tuple(gen(d) for d in deques)538```539540После того как [`tee()`](https://python-all.ru/3.7/library/itertools.html#itertools.tee) выполнил разделение, исходный *итерируемый объект* не следует использовать где-либо ещё; в противном случае *итерируемый объект* может продвинуться без уведомления объектов tee.541542Итераторы `tee` не являются потокобезопасными. [`RuntimeError`](https://python-all.ru/3.7/library/exceptions.html#RuntimeError) может быть возбуждён при одновременном использовании итераторов, возвращённых одним и тем же вызовом [`tee()`](https://python-all.ru/3.7/library/itertools.html#itertools.tee), даже если исходный *iterable* является потокобезопасным.543544Этот инструмент итерации может потребовать значительного вспомогательного хранилища (в зависимости от объёма временных данных, которые необходимо сохранить). В общем случае, если один итератор использует большую часть или все данные до того, как запустится другой итератор, быстрее использовать [`list()`](https://python-all.ru/3.7/library/stdtypes.html#list) вместо [`tee()`](https://python-all.ru/3.7/library/itertools.html#itertools.tee).545546#### `itertools.zip_longest(*iterables, fillvalue=None)`547548Создаёт итератор, который агрегирует элементы из каждого из итерируемых объектов. Если итерируемые объекты имеют разную длину, недостающие значения заполняются с помощью *fillvalue*. Итерация продолжается до тех пор, пока самый длинный итерируемый объект не будет исчерпан. Приблизительно эквивалентно:549550```python551def zip_longest(*args, fillvalue=None):552    # zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-553    iterators = [iter(it) for it in args]554    num_active = len(iterators)555    if not num_active:556        return557    while True:558        values = []559        for i, it in enumerate(iterators):560            try:561                value = next(it)562            except StopIteration:563                num_active -= 1564                if not num_active:565                    return566                iterators[i] = repeat(fillvalue)567                value = fillvalue568            values.append(value)569        yield tuple(values)570```571572Если один из итерируемых объектов потенциально бесконечен, то функцию [`zip_longest()`](https://python-all.ru/3.7/library/itertools.html#itertools.zip_longest) следует обернуть чем-то, что ограничивает количество вызовов (например, [`islice()`](https://python-all.ru/3.7/library/itertools.html#itertools.islice) или [`takewhile()`](https://python-all.ru/3.7/library/itertools.html#itertools.takewhile)). Если не указано, *fillvalue* по умолчанию равен `None`.573574## Рецепты itertools575576В этом разделе представлены рецепты для создания расширенного набора инструментов с использованием существующих itertools в качестве строительных блоков.577578Расширенные инструменты обеспечивают такую же высокую производительность, как и базовый набор инструментов. Превосходная производительность по памяти достигается за счёт обработки элементов по одному, а не загрузки всего итерируемого объекта в память сразу. Объём кода остаётся небольшим благодаря связыванию инструментов в функциональном стиле, что помогает избавиться от временных переменных. Высокая скорость сохраняется за счёт предпочтения «векторизованных» строительных блоков вместо использования циклов for и [генераторов](https://python-all.ru/3.7/glossary.html#term-generator), которые создают накладные расходы интерпретатора.579580```python581def take(n, iterable):582    "Return first n items of the iterable as a list"583    return list(islice(iterable, n))584585def prepend(value, iterator):586    "Prepend a single value in front of an iterator"587    # prepend(1, [2, 3, 4]) -> 1 2 3 4588    return chain([value], iterator)589590def tabulate(function, start=0):591    "Return function(0), function(1), ..."592    return map(function, count(start))593594def tail(n, iterable):595    "Return an iterator over the last n items"596    # tail(3, 'ABCDEFG') --> E F G597    return iter(collections.deque(iterable, maxlen=n))598599def consume(iterator, n=None):600    "Advance the iterator n-steps ahead. If n is None, consume entirely."601    # Используйте функции, потребляющие итераторы на скорости C.602    if n is None:603        # передать весь итератор в deque нулевой длины604        collections.deque(iterator, maxlen=0)605    else:606        # перейти к пустому срезу начиная с позиции n607        next(islice(iterator, n, n), None)608609def nth(iterable, n, default=None):610    "Returns the nth item or a default value"611    return next(islice(iterable, n, None), default)612613def all_equal(iterable):614    "Returns True if all the elements are equal to each other"615    g = groupby(iterable)616    return next(g, True) and not next(g, False)617618def quantify(iterable, pred=bool):619    "Count how many times the predicate is true"620    return sum(map(pred, iterable))621622def padnone(iterable):623    """Возвращает элементы последовательности, а затем бесконечно возвращает None.624625    Полезно для эмуляции поведения встроенной функции map().626    """627    return chain(iterable, repeat(None))628629def ncycles(iterable, n):630    "Returns the sequence elements n times"631    return chain.from_iterable(repeat(tuple(iterable), n))632633def dotproduct(vec1, vec2):634    return sum(map(operator.mul, vec1, vec2))635636def flatten(listOfLists):637    "Flatten one level of nesting"638    return chain.from_iterable(listOfLists)639640def repeatfunc(func, times=None, *args):641    """Повторяет вызовы func с указанными аргументами.642643    Пример:  repeatfunc(random.random)644    """645    if times is None:646        return starmap(func, repeat(args))647    return starmap(func, repeat(args, times))648649def pairwise(iterable):650    "s -> (s0,s1), (s1,s2), (s2, s3), ..."651    a, b = tee(iterable)652    next(b, None)653    return zip(a, b)654655def grouper(iterable, n, fillvalue=None):656    "Collect data into fixed-length chunks or blocks"657    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"658    args = [iter(iterable)] * n659    return zip_longest(*args, fillvalue=fillvalue)660661def roundrobin(*iterables):662    "roundrobin('ABC', 'D', 'EF') --> A D E B F C"663    # Автор рецепта – Джордж Саккис664    num_active = len(iterables)665    nexts = cycle(iter(it).__next__ for it in iterables)666    while num_active:667        try:668            for next in nexts:669                yield next()670        except StopIteration:671            # Удалить из цикла только что исчерпанный итератор.672            num_active -= 1673            nexts = cycle(islice(nexts, num_active))674675def partition(pred, iterable):676    'Use a predicate to partition entries into false entries and true entries'677    # partition(is_odd, range(10)) --> 0 2 4 6 8   и   1 3 5 7 9678    t1, t2 = tee(iterable)679    return filterfalse(pred, t1), filter(pred, t2)680681def powerset(iterable):682    "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"683    s = list(iterable)684    return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))685686def unique_everseen(iterable, key=None):687    "List unique elements, preserving order. Remember all elements ever seen."688    # unique_everseen('AAAABBBCCDAABBB') --> A B C D689    # unique_everseen('ABBCcAD', str.lower) --> A B C D690    seen = set()691    seen_add = seen.add692    if key is None:693        for element in filterfalse(seen.__contains__, iterable):694            seen_add(element)695            yield element696    else:697        for element in iterable:698            k = key(element)699            if k not in seen:700                seen_add(k)701                yield element702703def unique_justseen(iterable, key=None):704    "List unique elements, preserving order. Remember only the element just seen."705    # unique_justseen('AAAABBBCCDAABBB') --> A B C D A B706    # unique_justseen('ABBCcAD', str.lower) --> A B C A D707    return map(next, map(itemgetter(1), groupby(iterable, key)))708709def iter_except(func, exception, first=None):710    """ Повторно вызывает функцию до возникновения исключения.711712    Преобразует интерфейс вызова до исключения в интерфейс итератора.713    Как builtins.iter(func, sentinel), но использует исключение вместо714    сигнального значения для завершения цикла.715716    Примеры:717        iter_except(functools.partial(heappop, h), IndexError)   # итератор очереди с приоритетом718        iter_except(d.popitem, KeyError)                         # итератор словаря без блокировки719        iter_except(d.popleft, IndexError)                       # итератор дека без блокировки720        iter_except(q.get_nowait, Queue.Empty)                   # цикл по очереди производителя721        iter_except(s.pop, KeyError)                             # итератор множества без блокировки722723    """724    try:725        if first is not None:726            yield first()            # Для API баз данных, требующих первоначального приведения к db.first()727        while True:728            yield func()729    except exception:730        pass731732def first_true(iterable, default=False, pred=None):733    """Возвращает первое истинное значение в итерируемом объекте.734735    Если истинное значение не найдено, возвращает *default*736737    Если *pred* не равен None, возвращает первый элемент738    для которого pred(item) истинно.739740    """741    # first_true([a,b,c], x) --> a или b или c или x742    # first_true([a,b], x, f) --> a если f(a) иначе b если f(b) иначе x743    return next(filter(pred, iterable), default)744745def random_product(*args, repeat=1):746    "Random selection from itertools.product(*args, **kwds)"747    pools = [tuple(pool) for pool in args] * repeat748    return tuple(random.choice(pool) for pool in pools)749750def random_permutation(iterable, r=None):751    "Random selection from itertools.permutations(iterable, r)"752    pool = tuple(iterable)753    r = len(pool) if r is None else r754    return tuple(random.sample(pool, r))755756def random_combination(iterable, r):757    "Random selection from itertools.combinations(iterable, r)"758    pool = tuple(iterable)759    n = len(pool)760    indices = sorted(random.sample(range(n), r))761    return tuple(pool[i] for i in indices)762763def random_combination_with_replacement(iterable, r):764    "Random selection from itertools.combinations_with_replacement(iterable, r)"765    pool = tuple(iterable)766    n = len(pool)767    indices = sorted(random.randrange(n) for i in range(r))768    return tuple(pool[i] for i in indices)769770def nth_combination(iterable, r, index):771    'Equivalent to list(combinations(iterable, r))[index]'772    pool = tuple(iterable)773    n = len(pool)774    if r < 0 or r > n:775        raise ValueError776    c = 1777    k = min(r, n-r)778    for i in range(1, k+1):779        c = c * (n - k + i) // i780    if index < 0:781        index += c782    if index < 0 or index >= c:783        raise IndexError784    result = []785    while r:786        c, n, r = c*r//n, n-1, r-1787        while index >= c:788            index -= c789            c, n = c*(n-r)//n, n-1790        result.append(pool[-1-n])791    return tuple(result)792```793794Обратите внимание: многие из приведённых выше рецептов можно оптимизировать, заменив глобальные поиски локальными переменными, определёнными как значения по умолчанию. Например, рецепт *dotproduct* можно записать так:795796```python797def dotproduct(vec1, vec2, sum=sum, map=map, mul=operator.mul):798    return sum(map(mul, vec1, vec2))799```800