itertools.md
1> **Источник:** https://python-all.ru/3.6/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.6/library/itertools.html#module-itertools) – Функции, создающие итераторы для эффективного перебора89---1011Этот модуль реализует ряд строительных блоков [итераторов](https://python-all.ru/3.6/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.6/library/functions.html#map) и [`count()`](https://python-all.ru/3.6/library/itertools.html#itertools.count) для получения `map(f, count())`.1617Эти инструменты и их встроенные аналоги также хорошо работают с высокоскоростными функциями из модуля [`operator`](https://python-all.ru/3.6/library/operator.html#module-operator). Например, оператор умножения можно применить к двум векторам, чтобы получить эффективное скалярное произведение: `sum(map(operator.mul, vector1, vector2))`.1819**Бесконечные итераторы:**2021| Итератор | Аргументы | Результаты | Пример |22| --- | --- | --- | --- |23| [`count()`](https://python-all.ru/3.6/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.6/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.6/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.6/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.6/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.6/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.6/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.6/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.6/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.6/library/itertools.html#itertools.groupby) | iterable\[, key\] | подитераторы, сгруппированные по значению key(v) | |38| [`islice()`](https://python-all.ru/3.6/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.6/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.6/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.6/library/itertools.html#itertools.tee) | it, n | it1, it2, … itn разделяет один итератор на n | |42| [`zip_longest()`](https://python-all.ru/3.6/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.6/library/itertools.html#itertools.product) | p, q, … \[repeat=1\] | декартово произведение, эквивалентно вложенному циклу for |49| [`permutations()`](https://python-all.ru/3.6/library/itertools.html#itertools.permutations) | p\[, r\] | кортежи длиной r, все возможные перестановки, без повторяющихся элементов |50| [`combinations()`](https://python-all.ru/3.6/library/itertools.html#itertools.combinations) | p, r | кортежи длиной r, в отсортированном порядке, без повторяющихся элементов |51| [`combinations_with_replacement()`](https://python-all.ru/3.6/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## 10.1.1. Функции itertools5859Следующие функции модуля создают и возвращают итераторы. Некоторые из них порождают потоки бесконечной длины, поэтому обращаться к ним следует только с помощью функций или циклов, которые обрывают поток.6061#### `itertools.accumulate(iterable[, func])`6263Создаёт итератор, возвращающий накопленные суммы или накопленные результаты других бинарных функций (задаваемых необязательным аргументом *func*). Если *func* указана, это должна быть функция двух аргументов. Элементы входного *iterable* могут быть любого типа, который может быть принят в качестве аргумента *func*. (Например, при стандартной операции сложения элементы могут быть любого складываемого типа, включая [`Decimal`](https://python-all.ru/3.6/library/decimal.html#decimal.Decimal) или [`Fraction`](https://python-all.ru/3.6/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.6/library/functions.html#min) для текущего минимума, [`max()`](https://python-all.ru/3.6/library/functions.html#max) для текущего максимума или [`operator.mul()`](https://python-all.ru/3.6/library/operator.html#operator.mul) для текущего произведения. Таблицы амортизации можно построить, накапливая проценты и применяя платежи. [Рекуррентные соотношения](https://python-all.ru/3.6/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.6/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.6/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Комбинации выдаются в лексикографическом порядке. Таким образом, если входной *итерируемый объект* отсортирован, кортежи комбинаций будут созданы в отсортированном порядке.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.6/library/itertools.html#itertools.combinations) можно также выразить как подпоследовательность [`permutations()`](https://python-all.ru/3.6/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.6/library/itertools.html#itertools.combinations_with_replacement) можно также выразить как подпоследовательность [`product()`](https://python-all.ru/3.6/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.6/library/functions.html#map) для генерации последовательных точек данных. Также используется с [`zip()`](https://python-all.ru/3.6/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.6/library/itertools.html#itertools.groupby) аналогична фильтру `uniq` в Unix. Она создает разрыв или новую группу каждый раз, когда изменяется значение ключевой функции (поэтому обычно необходимо отсортировать данные с помощью той же ключевой функции). Такое поведение отличается от SQL GROUP BY, которая объединяет общие элементы независимо от порядка их ввода.311312Возвращаемая группа сама является итератором, который использует общий исходный итерируемый объект с [`groupby()`](https://python-all.ru/3.6/library/itertools.html#itertools.groupby). Поскольку источник общий, при продвижении объекта [`groupby()`](https://python-all.ru/3.6/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.6/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 while self.currkey == self.tgtkey:339 self.currvalue = next(self.it) # Выход при StopIteration340 self.currkey = self.keyfunc(self.currvalue)341 self.tgtkey = self.currkey342 return (self.currkey, self._grouper(self.tgtkey))343 def _grouper(self, tgtkey):344 while self.currkey == tgtkey:345 yield self.currvalue346 try:347 self.currvalue = next(self.it)348 except StopIteration:349 return350 self.currkey = self.keyfunc(self.currvalue)351```352353#### `itertools.islice(iterable, stop)`354355#### `itertools.islice(iterable, start, stop[, step])`356357Создаёт итератор, который возвращает выбранные элементы из итерируемого объекта. Если *start* не равен нулю, то элементы из итерируемого объекта пропускаются до достижения start. Затем элементы возвращаются последовательно, если только *step* не установлен больше единицы, что приводит к пропуску элементов. Если *stop* равен `None`, то итерация продолжается до тех пор, пока итератор не будет исчерпан, если вообще; в противном случае она останавливается на указанной позиции. В отличие от обычной срезки, [`islice()`](https://python-all.ru/3.6/library/itertools.html#itertools.islice) не поддерживает отрицательные значения для *start*, *stop* или *step*. Может использоваться для извлечения связанных полей из данных, где внутренняя структура была уплощена (например, многострочный отчёт может содержать поле имени на каждой третьей строке). Примерно эквивалентно:358359```python360def islice(iterable, *args):361 # islice('ABCDEFG', 2) --> A B362 # islice('ABCDEFG', 2, 4) --> C D363 # islice('ABCDEFG', 2, None) --> C D E F G364 # islice('ABCDEFG', 0, None, 2) --> A C E G365 s = slice(*args)366 start, stop, step = s.start or 0, s.stop or sys.maxsize, s.step or 1367 it = iter(range(start, stop, step))368 try:369 nexti = next(it)370 except StopIteration:371 # Потребляет *iterable* до позиции *start*.372 for i, element in zip(range(start), iterable):373 pass374 return375 try:376 for i, element in enumerate(iterable):377 if i == nexti:378 yield element379 nexti = next(it)380 except StopIteration:381 # Потребляет до *stop*.382 for i, element in zip(range(i + 1, stop), iterable):383 pass384```385386Если *start* равен `None`, то итерация начинается с нуля. Если *step* равен `None`, то шаг по умолчанию равен единице.387388#### `itertools.permutations(iterable, r=None)`389390Возвращает последовательные перестановки длины *r* элементов из *iterable*.391392Если *r* не указан или равен `None`, то *r* по умолчанию равен длине *iterable* и генерируются все возможные перестановки полной длины.393394Перестановки выдаются в лексикографическом порядке. Таким образом, если входной *итерируемый объект* отсортирован, кортежи перестановок будут созданы в отсортированном порядке.395396Элементы считаются уникальными на основе их позиции, а не значения. Поэтому если входные элементы уникальны, то в каждой перестановке не будет повторяющихся значений.397398Примерно эквивалентно:399400```python401def permutations(iterable, r=None):402 # permutations('ABCD', 2) --> AB AC AD BA BC BD CA CB CD DA DB DC403 # permutations(range(3)) --> 012 021 102 120 201 210404 pool = tuple(iterable)405 n = len(pool)406 r = n if r is None else r407 if r > n:408 return409 indices = list(range(n))410 cycles = list(range(n, n-r, -1))411 yield tuple(pool[i] for i in indices[:r])412 while n:413 for i in reversed(range(r)):414 cycles[i] -= 1415 if cycles[i] == 0:416 indices[i:] = indices[i+1:] + indices[i:i+1]417 cycles[i] = n - i418 else:419 j = cycles[i]420 indices[i], indices[-j] = indices[-j], indices[i]421 yield tuple(pool[i] for i in indices[:r])422 break423 else:424 return425```426427Код для [`permutations()`](https://python-all.ru/3.6/library/itertools.html#itertools.permutations) также можно выразить как подпоследовательность [`product()`](https://python-all.ru/3.6/library/itertools.html#itertools.product), отфильтрованную для исключения записей с повторяющимися элементами (тех, которые находятся на одной и той же позиции во входном пуле):428429```python430def permutations(iterable, r=None):431 pool = tuple(iterable)432 n = len(pool)433 r = n if r is None else r434 for indices in product(range(n), repeat=r):435 if len(set(indices)) == r:436 yield tuple(pool[i] for i in indices)437```438439Количество возвращаемых элементов равно `n! / (n-r)!`, когда `0 <= r <= n`, или нулю, когда `r > n`.440441#### `itertools.product(*iterables, repeat=1)`442443Декартово произведение входных итерируемых объектов.444445Примерно эквивалентно вложенным циклам for в генераторном выражении. Например, `product(A, B)` возвращает то же, что и `((x,y) for x in A for y in B)`.446447Вложенные циклы работают как одометр: самый правый элемент увеличивается на каждой итерации. Этот шаблон создает лексикографический порядок, так что если входные итерируемые объекты отсортированы, кортежи произведения выдаются в отсортированном порядке.448449Чтобы вычислить произведение итерируемого объекта на самого себя, укажите количество повторений с помощью необязательного именованного аргумента *repeat*. Например, `product(A, repeat=4)` эквивалентно `product(A, A, A, A)`.450451Эта функция примерно эквивалентна следующему коду, за исключением того, что реальная реализация не накапливает промежуточные результаты в памяти:452453```python454def product(*args, repeat=1):455 # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy456 # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111457 pools = [tuple(pool) for pool in args] * repeat458 result = [[]]459 for pool in pools:460 result = [x+[y] for x in result for y in pool]461 for prod in result:462 yield tuple(prod)463```464465#### `itertools.repeat(object[, times])`466467Создаёт итератор, который снова и снова возвращает *object*. Выполняется бесконечно, если не указан аргумент *times*. Используется как аргумент [`map()`](https://python-all.ru/3.6/library/functions.html#map) для инвариантных параметров вызываемой функции. Также используется с [`zip()`](https://python-all.ru/3.6/library/functions.html#zip) для создания инвариантной части кортежной записи.468469Примерно эквивалентно:470471```python472def repeat(object, times=None):473 # repeat(10, 3) --> 10 10 10474 if times is None:475 while True:476 yield object477 else:478 for i in range(times):479 yield object480```481482Обычное применение *repeat* – передача потока постоянных значений в *map* или *zip*:483484```python485>>> list(map(pow, range(10), repeat(2)))486[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]487```488489#### `itertools.starmap(function, iterable)`490491Создаёт итератор, который вычисляет функцию, используя аргументы, полученные из итерируемого объекта. Используется вместо [`map()`](https://python-all.ru/3.6/library/functions.html#map), когда параметры аргументов уже сгруппированы в кортежи из одного итерируемого объекта (данные были «предварительно сжаты»). Разница между [`map()`](https://python-all.ru/3.6/library/functions.html#map) и [`starmap()`](https://python-all.ru/3.6/library/itertools.html#itertools.starmap) параллельна различию между `function(a,b)` и `function(*c)`. Примерно эквивалентно:492493```python494def starmap(function, iterable):495 # starmap(pow, [(2,5), (3,2), (10,3)]) --> 32 9 1000496 for args in iterable:497 yield function(*args)498```499500#### `itertools.takewhile(predicate, iterable)`501502Создаёт итератор, возвращающий элементы из итерируемого объекта, пока предикат истинен. Приблизительно эквивалентно:503504```python505def takewhile(predicate, iterable):506 # takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4507 for x in iterable:508 if predicate(x):509 yield x510 else:511 break512```513514#### `itertools.tee(iterable, n=2)`515516Возвращает *n* независимых итераторов из одного итерируемого объекта.517518Следующий код на Python помогает объяснить, что делает *tee* (хотя реальная реализация более сложна и использует только одну базовую очередь FIFO).519520Примерно эквивалентно:521522```python523def tee(iterable, n=2):524 it = iter(iterable)525 deques = [collections.deque() for i in range(n)]526 def gen(mydeque):527 while True:528 if not mydeque: # когда локальная deque пуста529 try:530 newval = next(it) # извлечь новое значение и531 except StopIteration:532 return533 for d in deques: # загрузить его во все двусторонние очереди534 d.append(newval)535 yield mydeque.popleft()536 return tuple(gen(d) for d in deques)537```538539После того как [`tee()`](https://python-all.ru/3.6/library/itertools.html#itertools.tee) выполнил разделение, исходный *итерируемый объект* не следует использовать где-либо ещё; в противном случае *итерируемый объект* может продвинуться без уведомления объектов tee.540541Этот инструмент итерации может потребовать значительного вспомогательного хранилища (в зависимости от объёма временных данных, которые необходимо сохранить). В общем случае, если один итератор использует большую часть или все данные до того, как запустится другой итератор, быстрее использовать [`list()`](https://python-all.ru/3.6/library/stdtypes.html#list) вместо [`tee()`](https://python-all.ru/3.6/library/itertools.html#itertools.tee).542543#### `itertools.zip_longest(*iterables, fillvalue=None)`544545Создаёт итератор, который агрегирует элементы из каждого из итерируемых объектов. Если итерируемые объекты имеют разную длину, недостающие значения заполняются с помощью *fillvalue*. Итерация продолжается до тех пор, пока самый длинный итерируемый объект не будет исчерпан. Приблизительно эквивалентно:546547```python548class ZipExhausted(Exception):549 pass550551def zip_longest(*args, **kwds):552 # zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-553 fillvalue = kwds.get('fillvalue')554 counter = len(args) - 1555 def sentinel():556 nonlocal counter557 if not counter:558 raise ZipExhausted559 counter -= 1560 yield fillvalue561 fillers = repeat(fillvalue)562 iterators = [chain(it, sentinel(), fillers) for it in args]563 try:564 while iterators:565 yield tuple(map(next, iterators))566 except ZipExhausted:567 pass568```569570Если один из итерируемых объектов потенциально бесконечен, то функцию [`zip_longest()`](https://python-all.ru/3.6/library/itertools.html#itertools.zip_longest) следует обернуть чем-то, что ограничивает количество вызовов (например, [`islice()`](https://python-all.ru/3.6/library/itertools.html#itertools.islice) или [`takewhile()`](https://python-all.ru/3.6/library/itertools.html#itertools.takewhile)). Если не указано, *fillvalue* по умолчанию равен `None`.571572## 10.1.2. Рецепты itertools573574В этом разделе представлены рецепты для создания расширенного набора инструментов с использованием существующих itertools в качестве строительных блоков.575576Расширенные инструменты обеспечивают такую же высокую производительность, как и базовый набор инструментов. Превосходная производительность по памяти достигается за счёт обработки элементов по одному, а не загрузки всего итерируемого объекта в память сразу. Объём кода остаётся небольшим благодаря связыванию инструментов в функциональном стиле, что помогает избавиться от временных переменных. Высокая скорость сохраняется за счёт предпочтения «векторизованных» строительных блоков вместо использования циклов for и [генераторов](https://python-all.ru/3.6/glossary.html#term-generator), которые создают накладные расходы интерпретатора.577578```python579def take(n, iterable):580 "Return first n items of the iterable as a list"581 return list(islice(iterable, n))582583def prepend(value, iterator):584 "Prepend a single value in front of an iterator"585 # prepend(1, [2, 3, 4]) -> 1 2 3 4586 return chain([value], iterator)587588def tabulate(function, start=0):589 "Return function(0), function(1), ..."590 return map(function, count(start))591592def tail(n, iterable):593 "Return an iterator over the last n items"594 # tail(3, 'ABCDEFG') --> E F G595 return iter(collections.deque(iterable, maxlen=n))596597def consume(iterator, n=None):598 "Advance the iterator n-steps ahead. If n is None, consume entirely."599 # Используйте функции, потребляющие итераторы на скорости C.600 if n is None:601 # передать весь итератор в deque нулевой длины602 collections.deque(iterator, maxlen=0)603 else:604 # перейти к пустому срезу начиная с позиции n605 next(islice(iterator, n, n), None)606607def nth(iterable, n, default=None):608 "Returns the nth item or a default value"609 return next(islice(iterable, n, None), default)610611def all_equal(iterable):612 "Returns True if all the elements are equal to each other"613 g = groupby(iterable)614 return next(g, True) and not next(g, False)615616def quantify(iterable, pred=bool):617 "Count how many times the predicate is true"618 return sum(map(pred, iterable))619620def padnone(iterable):621 """Возвращает элементы последовательности, а затем бесконечно возвращает None.622623 Полезно для эмуляции поведения встроенной функции map().624 """625 return chain(iterable, repeat(None))626627def ncycles(iterable, n):628 "Returns the sequence elements n times"629 return chain.from_iterable(repeat(tuple(iterable), n))630631def dotproduct(vec1, vec2):632 return sum(map(operator.mul, vec1, vec2))633634def flatten(listOfLists):635 "Flatten one level of nesting"636 return chain.from_iterable(listOfLists)637638def repeatfunc(func, times=None, *args):639 """Повторяет вызовы func с указанными аргументами.640641 Пример: repeatfunc(random.random)642 """643 if times is None:644 return starmap(func, repeat(args))645 return starmap(func, repeat(args, times))646647def pairwise(iterable):648 "s -> (s0,s1), (s1,s2), (s2, s3), ..."649 a, b = tee(iterable)650 next(b, None)651 return zip(a, b)652653def grouper(iterable, n, fillvalue=None):654 "Collect data into fixed-length chunks or blocks"655 # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"656 args = [iter(iterable)] * n657 return zip_longest(*args, fillvalue=fillvalue)658659def roundrobin(*iterables):660 "roundrobin('ABC', 'D', 'EF') --> A D E B F C"661 # Автор рецепта – Джордж Саккис662 num_active = len(iterables)663 nexts = cycle(iter(it).__next__ for it in iterables)664 while num_active:665 try:666 for next in nexts:667 yield next()668 except StopIteration:669 # Удалить из цикла только что исчерпанный итератор.670 num_active -= 1671 nexts = cycle(islice(nexts, num_active))672673def partition(pred, iterable):674 'Use a predicate to partition entries into false entries and true entries'675 # partition(is_odd, range(10)) --> 0 2 4 6 8 и 1 3 5 7 9676 t1, t2 = tee(iterable)677 return filterfalse(pred, t1), filter(pred, t2)678679def powerset(iterable):680 "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"681 s = list(iterable)682 return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))683684def unique_everseen(iterable, key=None):685 "List unique elements, preserving order. Remember all elements ever seen."686 # unique_everseen('AAAABBBCCDAABBB') --> A B C D687 # unique_everseen('ABBCcAD', str.lower) --> A B C D688 seen = set()689 seen_add = seen.add690 if key is None:691 for element in filterfalse(seen.__contains__, iterable):692 seen_add(element)693 yield element694 else:695 for element in iterable:696 k = key(element)697 if k not in seen:698 seen_add(k)699 yield element700701def unique_justseen(iterable, key=None):702 "List unique elements, preserving order. Remember only the element just seen."703 # unique_justseen('AAAABBBCCDAABBB') --> A B C D A B704 # unique_justseen('ABBCcAD', str.lower) --> A B C A D705 return map(next, map(itemgetter(1), groupby(iterable, key)))706707def iter_except(func, exception, first=None):708 """ Повторно вызывает функцию до возникновения исключения.709710 Преобразует интерфейс вызова до исключения в интерфейс итератора.711 Как builtins.iter(func, sentinel), но использует исключение вместо712 сигнального значения для завершения цикла.713714 Примеры:715 iter_except(functools.partial(heappop, h), IndexError) # итератор очереди с приоритетом716 iter_except(d.popitem, KeyError) # итератор словаря без блокировки717 iter_except(d.popleft, IndexError) # итератор дека без блокировки718 iter_except(q.get_nowait, Queue.Empty) # цикл по очереди производителя719 iter_except(s.pop, KeyError) # итератор множества без блокировки720721 """722 try:723 if first is not None:724 yield first() # Для API баз данных, требующих первоначального приведения к db.first()725 while True:726 yield func()727 except exception:728 pass729730def first_true(iterable, default=False, pred=None):731 """Возвращает первое истинное значение в итерируемом объекте.732733 Если истинное значение не найдено, возвращает *default*734735 Если *pred* не равен None, возвращает первый элемент736 для которого pred(item) истинно.737738 """739 # first_true([a,b,c], x) --> a или b или c или x740 # first_true([a,b], x, f) --> a если f(a) иначе b если f(b) иначе x741 return next(filter(pred, iterable), default)742743def random_product(*args, repeat=1):744 "Random selection from itertools.product(*args, **kwds)"745 pools = [tuple(pool) for pool in args] * repeat746 return tuple(random.choice(pool) for pool in pools)747748def random_permutation(iterable, r=None):749 "Random selection from itertools.permutations(iterable, r)"750 pool = tuple(iterable)751 r = len(pool) if r is None else r752 return tuple(random.sample(pool, r))753754def random_combination(iterable, r):755 "Random selection from itertools.combinations(iterable, r)"756 pool = tuple(iterable)757 n = len(pool)758 indices = sorted(random.sample(range(n), r))759 return tuple(pool[i] for i in indices)760761def random_combination_with_replacement(iterable, r):762 "Random selection from itertools.combinations_with_replacement(iterable, r)"763 pool = tuple(iterable)764 n = len(pool)765 indices = sorted(random.randrange(n) for i in range(r))766 return tuple(pool[i] for i in indices)767768def nth_combination(iterable, r, index):769 'Equivalent to list(combinations(iterable, r))[index]'770 pool = tuple(iterable)771 n = len(pool)772 if r < 0 or r > n:773 raise ValueError774 c = 1775 k = min(r, n-r)776 for i in range(1, k+1):777 c = c * (n - k + i) // i778 if index < 0:779 index += c780 if index < 0 or index >= c:781 raise IndexError782 result = []783 while r:784 c, n, r = c*r//n, n-1, r-1785 while index >= c:786 index -= c787 c, n = c*(n-r)//n, n-1788 result.append(pool[-1-n])789 return tuple(result)790```791792Обратите внимание: многие из приведённых выше рецептов можно оптимизировать, заменив глобальные поиски локальными переменными, определёнными как значения по умолчанию. Например, рецепт *dotproduct* можно записать так:793794```python795def dotproduct(vec1, vec2, sum=sum, map=map, mul=operator.mul):796 return sum(map(mul, vec1, vec2))797```798