itertools.md
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