itertools.md
1> **Источник:** https://python-all.ru/3.1/library/itertools.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 9.7. `itertools` – Функции, создающие итераторы для эффективного выполнения циклов89Этот модуль реализует ряд строительных блоков [*итераторов*](https://python-all.ru/3.1/glossary.html#term-iterator), вдохновлённых конструкциями из APL, Haskell и SML. Каждый из них переработан в форму, подходящую для Python.1011Модуль стандартизирует основной набор быстрых и эффективных по памяти инструментов, которые полезны сами по себе или в комбинации. Вместе они образуют «алгебру итераторов», позволяющую создавать специализированные инструменты кратко и эффективно на чистом Python.1213Например, в SML есть инструмент табуляции: `tabulate(f)`, который создаёт последовательность `f(0), f(1), ...`. Того же эффекта в Python можно добиться, объединив [`map()`](https://python-all.ru/3.1/library/functions.html#map) и [`count()`](https://python-all.ru/3.1/library/itertools.html#itertools.count), чтобы получить `map(f, count())`.1415Эти инструменты и их встроенные аналоги также хорошо работают с высокоскоростными функциями из модуля [`operator`](https://python-all.ru/3.1/library/operator.html#module-operator). Например, оператор умножения можно применить к двум векторам, чтобы вычислить эффективное скалярное произведение: `sum(map(operator.mul, vector1, vector2))`.1617**Бесконечные итераторы:**1819| Итератор | Аргументы | Результаты | Пример |20| --- | --- | --- | --- |21| [`count()`](https://python-all.ru/3.1/library/itertools.html#itertools.count) | start, \[step\] | start, start+step, start+2\*step, ... | `count(10) --> 10 11 12 13 14 ...` |22| [`cycle()`](https://python-all.ru/3.1/library/itertools.html#itertools.cycle) | p | p0, p1, ... plast, p0, p1, ... | `cycle('ABCD') --> A B C D A B C D ...` |23| [`repeat()`](https://python-all.ru/3.1/library/itertools.html#itertools.repeat) | elem \[,n\] | elem, elem, elem, ... бесконечно или до n раз | `repeat(10, 3) --> 10 10 10` |2425**Итераторы, завершающиеся по кратчайшей входной последовательности:**2627| Итератор | Аргументы | Результаты | Пример |28| --- | --- | --- | --- |29| [`chain()`](https://python-all.ru/3.1/library/itertools.html#itertools.chain) | p, q, ... | p0, p1, ... plast, q0, q1, ... | `chain('ABC', 'DEF') --> A B C D E F` |30| [`compress()`](https://python-all.ru/3.1/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` |31| [`dropwhile()`](https://python-all.ru/3.1/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` |32| [`filterfalse()`](https://python-all.ru/3.1/library/itertools.html#itertools.filterfalse) | pred, seq | элементы seq, для которых pred(elem) равно False | `filterfalse(lambda x: x%2, range(10)) --> 0 2 4 6 8` |33| [`groupby()`](https://python-all.ru/3.1/library/itertools.html#itertools.groupby) | iterable\[, keyfunc\] | под-итераторы, сгруппированные по значению keyfunc(v) | |34| [`islice()`](https://python-all.ru/3.1/library/itertools.html#itertools.islice) | seq, \[start,\] stop \[, step\] | элементы из seq\[start:stop:step\] | `islice('ABCDEFG', 2, None) --> C D E F G` |35| [`starmap()`](https://python-all.ru/3.1/library/itertools.html#itertools.starmap) | func, seq | func(\*seq\[0\]), func(\*seq\[1\]), ... | `starmap(pow, [(2,5), (3,2), (10,3)]) --> 32 9 1000` |36| [`takewhile()`](https://python-all.ru/3.1/library/itertools.html#itertools.takewhile) | pred, seq | seq\[0\], seq\[1\], пока pred не вернёт ложь | `takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4` |37| [`tee()`](https://python-all.ru/3.1/library/itertools.html#itertools.tee) | it, n | it1, it2 , ... itn делит один итератор на n | |38| [`zip_longest()`](https://python-all.ru/3.1/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-` |3940**Комбинаторные генераторы:**4142| Итератор | Аргументы | Результаты |43| --- | --- | --- |44| [`product()`](https://python-all.ru/3.1/library/itertools.html#itertools.product) | p, q, ... \[repeat=1\] | декартово произведение, эквивалентно вложенному циклу for |45| [`permutations()`](https://python-all.ru/3.1/library/itertools.html#itertools.permutations) | p\[, r\] | кортежи длиной r, все возможные перестановки, без повторяющихся элементов |46| [`combinations()`](https://python-all.ru/3.1/library/itertools.html#itertools.combinations) | p, r | кортежи длиной r, в отсортированном порядке, без повторяющихся элементов |47| [`combinations_with_replacement()`](https://python-all.ru/3.1/library/itertools.html#itertools.combinations_with_replacement) | p, r | кортежи длиной r, в отсортированном порядке, с повторяющимися элементами |48| `product('ABCD', repeat=2)` | | `AA AB AC AD BA BB BC BD CA CB CC CD DA DB DC DD` |49| `permutations('ABCD', 2)` | | `AB AC AD BA BC BD CA CB CD DA DB DC` |50| `combinations('ABCD', 2)` | | `AB AC AD BC BD CD` |51| `combinations_with_replacement('ABCD', 2)` | | `AA AB AC AD BB BC BD CC CD DD` |5253## 9.7.1. Функции itertools5455Следующие функции модуля создают и возвращают итераторы. Некоторые из них порождают потоки бесконечной длины, поэтому обращаться к ним следует только с помощью функций или циклов, которые обрывают поток.5657#### `itertools.chain(*iterables)`5859Создаёт итератор, возвращающий элементы из первого итерируемого объекта до его исчерпания, затем переходит к следующему и так далее, пока все итерируемые объекты не будут исчерпаны. Используется для обработки последовательных последовательностей как одной последовательности. Эквивалентно:6061```python62def chain(*iterables):63 # chain('ABC', 'DEF') --> A B C D E F64 for it in iterables:65 for element in it:66 yield element67```6869#### `classmethod chain.from_iterable(iterable)`7071Альтернативный конструктор для [`chain()`](https://python-all.ru/3.1/library/itertools.html#itertools.chain). Получает цепочку входных данных из одного итерируемого аргумента, который вычисляется лениво. Эквивалентно:7273```python74@classmethod75def from_iterable(iterables):76 # chain.from_iterable(['ABC', 'DEF']) --> A B C D E F77 for it in iterables:78 for element in it:79 yield element80```8182#### `itertools.combinations(iterable, r)`8384Возвращает подпоследовательности элементов длины *r* из входного *iterable*.8586Комбинации выдаются в лексикографическом порядке. Таким образом, если входной *итерируемый объект* отсортирован, кортежи комбинаций будут созданы в отсортированном порядке.8788Элементы считаются уникальными на основе их позиции, а не значения. Поэтому если входные элементы уникальны, то в каждой комбинации не будет повторяющихся значений.8990Эквивалентно следующему:9192```python93def combinations(iterable, r):94 # combinations('ABCD', 2) --> AB AC AD BC BD CD95 # combinations(range(4), 3) --> 012 013 023 12396 pool = tuple(iterable)97 n = len(pool)98 if r > n:99 return100 indices = list(range(r))101 yield tuple(pool[i] for i in indices)102 while True:103 for i in reversed(range(r)):104 if indices[i] != i + n - r:105 break106 else:107 return108 indices[i] += 1109 for j in range(i+1, r):110 indices[j] = indices[j-1] + 1111 yield tuple(pool[i] for i in indices)112```113114Код для [`combinations()`](https://python-all.ru/3.1/library/itertools.html#itertools.combinations) также можно выразить как подпоследовательность [`permutations()`](https://python-all.ru/3.1/library/itertools.html#itertools.permutations) после фильтрации записей, в которых элементы не отсортированы (согласно их позиции во входном пуле):115116```python117def combinations(iterable, r):118 pool = tuple(iterable)119 n = len(pool)120 for indices in permutations(range(n), r):121 if sorted(indices) == list(indices):122 yield tuple(pool[i] for i in indices)123```124125Количество возвращаемых элементов равно `n! / r! / (n-r)!`, когда `0 <= r <= n`, или нулю, когда `r > n`.126127#### `itertools.combinations_with_replacement(iterable, r)`128129Возвращает подпоследовательности элементов длины *r* из входного *iterable*, допуская повторение отдельных элементов.130131Комбинации выдаются в лексикографическом порядке. Таким образом, если входной *итерируемый объект* отсортирован, кортежи комбинаций будут созданы в отсортированном порядке.132133Элементы считаются уникальными по их позиции, а не по значению. Поэтому если входные элементы уникальны, сгенерированные комбинации также будут уникальны.134135Эквивалентно следующему:136137```python138def combinations_with_replacement(iterable, r):139 # combinations_with_replacement('ABC', 2) --> AA AB AC BB BC CC140 pool = tuple(iterable)141 n = len(pool)142 if not n and r:143 return144 indices = [0] * r145 yield tuple(pool[i] for i in indices)146 while True:147 for i in reversed(range(r)):148 if indices[i] != n - 1:149 break150 else:151 return152 indices[i:] = [indices[i] + 1] * (r - i)153 yield tuple(pool[i] for i in indices)154```155156Код для [`combinations_with_replacement()`](https://python-all.ru/3.1/library/itertools.html#itertools.combinations_with_replacement) также можно выразить как подпоследовательность [`product()`](https://python-all.ru/3.1/library/itertools.html#itertools.product) после фильтрации записей, в которых элементы не отсортированы (согласно их позиции во входном пуле):157158```python159def combinations_with_replacement(iterable, r):160 pool = tuple(iterable)161 n = len(pool)162 for indices in product(range(n), repeat=r):163 if sorted(indices) == list(indices):164 yield tuple(pool[i] for i in indices)165```166167Количество возвращаемых элементов равно `(n+r-1)! / r! / (n-1)!`, когда `n > 0`.168169Новое в версии 3.1.170171#### `itertools.compress(data, selectors)`172173Создаёт итератор, который фильтрует элементы из *data*, возвращая только те, для которых соответствующий элемент в *selectors* вычисляется как `True`. Останавливается, когда исчерпан либо *data*, либо *selectors*. Эквивалентно:174175```python176def compress(data, selectors):177 # compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F178 return (d for d, s in zip(data, selectors) if s)179```180181Новое в версии 3.1.182183#### `itertools.count(start=0, step=1)`184185Создаёт итератор, возвращающий равномерно расположенные значения, начиная с *n*. Часто используется как аргумент для [`map()`](https://python-all.ru/3.1/library/functions.html#map) для генерации последовательных точек данных. Также используется с [`zip()`](https://python-all.ru/3.1/library/functions.html#zip) для добавления порядковых номеров. Эквивалентно:186187```python188def count(start=0, step=1):189 # count(10) --> 10 11 12 13 14 ...190 # count(2.5, 0.5) -> 2.5 3.0 3.5 ...191 n = start192 while True:193 yield n194 n += step195```196197При подсчёте с числами с плавающей запятой иногда можно добиться лучшей точности, заменив его на мультипликативный код, например: `(start + step * i for i in count())`.198199Изменено в версии 3.1: Добавлен аргумент *step* и разрешены нецелые аргументы.200201#### `itertools.cycle(iterable)`202203Создаёт итератор, возвращающий элементы из итерируемого объекта и сохраняющий копию каждого. Когда итерируемый объект исчерпан, возвращает элементы из сохранённой копии. Повторяется бесконечно. Эквивалентно:204205```python206def cycle(iterable):207 # cycle('ABCD') --> A B C D A B C D A B C D ...208 saved = []209 for element in iterable:210 yield element211 saved.append(element)212 while saved:213 for element in saved:214 yield element215```216217Примечание: этот элемент набора инструментов может потребовать значительного дополнительного хранилища (в зависимости от длины итерабельного объекта).218219#### `itertools.dropwhile(predicate, iterable)`220221Создаёт итератор, который отбрасывает элементы из итерируемого объекта, пока предикат истинен; после этого возвращает каждый элемент. Обратите внимание: итератор не выдаёт *никакого* вывода, пока предикат не станет ложным, поэтому время запуска может быть значительным. Эквивалентно:222223```python224def dropwhile(predicate, iterable):225 # dropwhile(lambda x: x<5, [1,4,6,4,1]) --> 6 4 1226 iterable = iter(iterable)227 for x in iterable:228 if not predicate(x):229 yield x230 break231 for x in iterable:232 yield x233```234235#### `itertools.filterfalse(predicate, iterable)`236237Создаёт итератор, который фильтрует элементы из итерируемого объекта, возвращая только те, для которых предикат равен `False`. Если *predicate* равен `None`, возвращает элементы, которые являются ложными. Эквивалентно.238239```python240def filterfalse(predicate, iterable):241 # filterfalse(lambda x: x%2, range(10)) --> 0 2 4 6 8242 if predicate is None:243 predicate = bool244 for x in iterable:245 if not predicate(x):246 yield x247```248249#### `itertools.groupby(iterable, key=None)`250251Создаёт итератор, который возвращает последовательные ключи и группы из *iterable*. *key* – это функция, вычисляющая ключевое значение для каждого элемента. Если он не указан или равен `None`, то *key* по умолчанию принимает тождественную функцию и возвращает элемент без изменений. Обычно iterable должен быть отсортирован по той же ключевой функции.252253Работа [`groupby()`](https://python-all.ru/3.1/library/itertools.html#itertools.groupby) похожа на фильтр `uniq` в Unix. Она создаёт разрыв или новую группу каждый раз, когда значение ключевой функции меняется (именно поэтому данные обычно необходимо отсортировать с помощью той же ключевой функции). Такое поведение отличается от SQL’s GROUP BY, которое объединяет общие элементы независимо от их порядка во входных данных.254255Возвращаемая группа сама является итератором, который использует тот же исходный итератор, что и [`groupby()`](https://python-all.ru/3.1/library/itertools.html#itertools.groupby). Поскольку источник общий, когда [`groupby()`](https://python-all.ru/3.1/library/itertools.html#itertools.groupby) объект продвигается, предыдущая группа перестаёт быть видимой. Поэтому, если эти данные потребуются позже, их следует сохранить в виде списка:256257```python258groups = []259uniquekeys = []260data = sorted(data, key=keyfunc)261for k, g in groupby(data, keyfunc):262 groups.append(list(g)) # Сохранить групповой итератор как список263 uniquekeys.append(k)264```265266[`groupby()`](https://python-all.ru/3.1/library/itertools.html#itertools.groupby) эквивалентен следующему:267268```python269class groupby:270 # [k for k, g in groupby('AAAABBBCCDAABBB')] --> A B C D A B271 # [list(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D272 def __init__(self, iterable, key=None):273 if key is None:274 key = lambda x: x275 self.keyfunc = key276 self.it = iter(iterable)277 self.tgtkey = self.currkey = self.currvalue = object()278 def __iter__(self):279 return self280 def __next__(self):281 while self.currkey == self.tgtkey:282 self.currvalue = next(self.it) # Выход при StopIteration283 self.currkey = self.keyfunc(self.currvalue)284 self.tgtkey = self.currkey285 return (self.currkey, self._grouper(self.tgtkey))286 def _grouper(self, tgtkey):287 while self.currkey == tgtkey:288 yield self.currvalue289 self.currvalue = next(self.it) # Выход при StopIteration290 self.currkey = self.keyfunc(self.currvalue)291```292293#### `itertools.islice(iterable[, start], stop[, step])`294295Создаёт итератор, который возвращает выбранные элементы из iterable. Если *start* не равен нулю, то элементы из iterable пропускаются до тех пор, пока не будет достигнут start. После этого элементы возвращаются подряд, если только *step* не больше единицы, что приводит к пропуску элементов. Если *stop* равен `None`, то итерация продолжается, пока итератор не исчерпается; в противном случае она останавливается на указанной позиции. В отличие от обычного среза, [`islice()`](https://python-all.ru/3.1/library/itertools.html#itertools.islice) не поддерживает отрицательные значения для *start*, *stop* или *step*. Может использоваться для извлечения связанных полей из данных, у которых внутренняя структура была сплющена (например, в многострочном отчёте поле имени может располагаться на каждой третьей строке). Эквивалентен:296297```python298def islice(iterable, *args):299 # islice('ABCDEFG', 2) --> A B300 # islice('ABCDEFG', 2, 4) --> C D301 # islice('ABCDEFG', 2, None) --> C D E F G302 # islice('ABCDEFG', 0, None, 2) --> A C E G303 s = slice(*args)304 it = iter(range(s.start or 0, s.stop or sys.maxsize, s.step or 1))305 nexti = next(it)306 for i, element in enumerate(iterable):307 if i == nexti:308 yield element309 nexti = next(it)310```311312Если *start* равен `None`, то итерация начинается с нуля. Если *step* равен `None`, то шаг по умолчанию равен единице.313314#### `itertools.permutations(iterable, r=None)`315316Возвращает последовательные перестановки длины *r* элементов из *iterable*.317318Если *r* не указан или равен `None`, то *r* по умолчанию принимает длину *iterable* и генерируются все возможные перестановки полной длины.319320Перестановки выдаются в лексикографическом порядке. Таким образом, если входной *итерируемый объект* отсортирован, кортежи перестановок будут созданы в отсортированном порядке.321322Элементы считаются уникальными на основе их позиции, а не значения. Поэтому если входные элементы уникальны, то в каждой перестановке не будет повторяющихся значений.323324Эквивалентно следующему:325326```python327def permutations(iterable, r=None):328 # permutations('ABCD', 2) --> AB AC AD BA BC BD CA CB CD DA DB DC329 # permutations(range(3)) --> 012 021 102 120 201 210330 pool = tuple(iterable)331 n = len(pool)332 r = n if r is None else r333 if r > n:334 return335 indices = list(range(n))336 cycles = range(n, n-r, -1)337 yield tuple(pool[i] for i in indices[:r])338 while n:339 for i in reversed(range(r)):340 cycles[i] -= 1341 if cycles[i] == 0:342 indices[i:] = indices[i+1:] + indices[i:i+1]343 cycles[i] = n - i344 else:345 j = cycles[i]346 indices[i], indices[-j] = indices[-j], indices[i]347 yield tuple(pool[i] for i in indices[:r])348 break349 else:350 return351```352353Код для [`permutations()`](https://python-all.ru/3.1/library/itertools.html#itertools.permutations) можно также выразить как подпоследовательность [`product()`](https://python-all.ru/3.1/library/itertools.html#itertools.product), отфильтрованную для исключения записей с повторяющимися элементами (тех, что находятся на одной и той же позиции во входном пуле):354355```python356def permutations(iterable, r=None):357 pool = tuple(iterable)358 n = len(pool)359 r = n if r is None else r360 for indices in product(range(n), repeat=r):361 if len(set(indices)) == r:362 yield tuple(pool[i] for i in indices)363```364365Количество возвращаемых элементов равно `n! / (n-r)!`, когда `0 <= r <= n` или нулю, когда `r > n`.366367#### `itertools.product(*iterables, repeat=1)`368369Декартово произведение входных итерируемых объектов.370371Эквивалентно вложенным циклам for в генераторном выражении. Например, `product(A, B)` возвращает то же, что и `((x,y) for x in A for y in B)`.372373Вложенные циклы работают как одометр: самый правый элемент увеличивается на каждой итерации. Этот шаблон создает лексикографический порядок, так что если входные итерируемые объекты отсортированы, кортежи произведения выдаются в отсортированном порядке.374375Чтобы вычислить произведение итератора самого на себя, укажите количество повторений с помощью необязательного именованного аргумента *repeat*. Например, `product(A, repeat=4)` означает то же, что и `product(A, A, A, A)`.376377Эта функция эквивалентна следующему коду, за исключением того, что реальная реализация не создаёт промежуточные результаты в памяти:378379```python380def product(*args, repeat=1):381 # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy382 # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111383 pools = [tuple(pool) for pool in args] * repeat384 result = [[]]385 for pool in pools:386 result = [x+[y] for x in result for y in pool]387 for prod in result:388 yield tuple(prod)389```390391#### `itertools.repeat(object[, times])`392393Создаёт итератор, который снова и снова возвращает *object*. Работает бесконечно, если не указан аргумент *times*. Используется как аргумент для [`map()`](https://python-all.ru/3.1/library/functions.html#map) для неизменяемых параметров вызываемой функции. Также используется с [`zip()`](https://python-all.ru/3.1/library/functions.html#zip) для создания неизменяемой части записи кортежа. Эквивалентен:394395```python396def repeat(object, times=None):397 # repeat(10, 3) --> 10 10 10398 if times is None:399 while True:400 yield object401 else:402 for i in range(times):403 yield object404```405406#### `itertools.starmap(function, iterable)`407408Создаёт итератор, который вычисляет функцию, используя аргументы, полученные из итератора. Используется вместо [`map()`](https://python-all.ru/3.1/library/functions.html#map), когда аргументы уже сгруппированы в кортежи из одного итератора (данные были «предварительно сжаты»). Разница между [`map()`](https://python-all.ru/3.1/library/functions.html#map) и [`starmap()`](https://python-all.ru/3.1/library/itertools.html#itertools.starmap) аналогична различию между `function(a,b)` и `function(*c)`. Эквивалентен:409410```python411def starmap(function, iterable):412 # starmap(pow, [(2,5), (3,2), (10,3)]) --> 32 9 1000413 for args in iterable:414 yield function(*args)415```416417#### `itertools.takewhile(predicate, iterable)`418419Создаёт итератор, который возвращает элементы из итератора, пока предикат истинен. Эквивалентен:420421```python422def takewhile(predicate, iterable):423 # takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4424 for x in iterable:425 if predicate(x):426 yield x427 else:428 break429```430431#### `itertools.tee(iterable, n=2)`432433Возвращает *n* независимых итераторов из одного итератора. Эквивалентен:434435```python436def tee(iterable, n=2):437 it = iter(iterable)438 deques = [collections.deque() for i in range(n)]439 def gen(mydeque):440 while True:441 if not mydeque: # когда локальная deque пуста442 newval = next(it) # извлечь новое значение и443 for d in deques: # загрузить его во все двусторонние очереди444 d.append(newval)445 yield mydeque.popleft()446 return tuple(gen(d) for d in deques)447```448449После того, как [`tee()`](https://python-all.ru/3.1/library/itertools.html#itertools.tee) произвел разделение, исходный *iterable* не должен использоваться где-либо ещё; в противном случае *iterable* может быть продвинут без уведомления объектов tee.450451Этот инструмент итерации может потребовать значительного объёма дополнительной памяти (в зависимости от того, сколько временных данных нужно сохранить). В общем случае, если один итератор использует большую часть или все данные до того, как запускается другой итератор, быстрее использовать [`list()`](https://python-all.ru/3.1/library/functions.html#list) вместо [`tee()`](https://python-all.ru/3.1/library/itertools.html#itertools.tee).452453#### `itertools.zip_longest(*iterables, fillvalue=None)`454455Создаёт итератор, который объединяет элементы из каждого из итераторов. Если итераторы имеют разную длину, отсутствующие значения заполняются с помощью *fillvalue*. Итерация продолжается, пока самый длинный итератор не будет исчерпан. Эквивалентен:456457```python458def zip_longest(*args, fillvalue=None):459 # zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-460 def sentinel(counter = ([fillvalue]*(len(args)-1)).pop):461 yield counter() # выдаёт fillvalue или вызывает IndexError462 fillers = repeat(fillvalue)463 iters = [chain(it, sentinel(), fillers) for it in args]464 try:465 for tup in zip(*iters):466 yield tup467 except IndexError:468 pass469```470471Если один из итераторов потенциально бесконечен, то функция [`zip_longest()`](https://python-all.ru/3.1/library/itertools.html#itertools.zip_longest) должна быть обёрнута чем-то, что ограничивает количество вызовов (например, [`islice()`](https://python-all.ru/3.1/library/itertools.html#itertools.islice) или [`takewhile()`](https://python-all.ru/3.1/library/itertools.html#itertools.takewhile)). Если не указано, *fillvalue* по умолчанию равен `None`.472473## 9.7.2. Рецепты474475В этом разделе представлены рецепты для создания расширенного набора инструментов с использованием существующих itertools в качестве строительных блоков.476477Расширенные инструменты обеспечивают такую же высокую производительность, как и базовый набор инструментов. Превосходная производительность по памяти достигается за счёт обработки элементов по одному, а не загрузки всего итерируемого объекта в память сразу. Объём кода остаётся небольшим благодаря связыванию инструментов в функциональном стиле, что помогает избавиться от временных переменных. Высокая скорость сохраняется за счёт предпочтения «векторизованных» строительных блоков вместо использования циклов for и [*генераторов*](https://python-all.ru/3.1/glossary.html#term-generator), которые создают накладные расходы интерпретатора.478479```python480def take(n, iterable):481 "Return first n items of the iterable as a list"482 return list(islice(iterable, n))483484def tabulate(function, start=0):485 "Return function(0), function(1), ..."486 return map(function, count(start))487488def consume(iterator, n):489 "Advance the iterator n-steps ahead. If n is none, consume entirely."490 # Используйте функции, потребляющие итераторы на скорости C.491 if n is None:492 # передать весь итератор в deque нулевой длины493 collections.deque(iterator, maxlen=0)494 else:495 # перейти к пустому срезу начиная с позиции n496 next(islice(iterator, n, n), None)497498def nth(iterable, n, default=None):499 "Returns the nth item or a default value"500 return next(islice(iterable, n, None), default)501502def quantify(iterable, pred=bool):503 "Count how many times the predicate is true"504 return sum(map(pred, iterable))505506def padnone(iterable):507 """Возвращает элементы последовательности, а затем бесконечно возвращает None.508509 Полезно для эмуляции поведения встроенной функции map().510 """511 return chain(iterable, repeat(None))512513def ncycles(iterable, n):514 "Returns the sequence elements n times"515 return chain.from_iterable(repeat(tuple(iterable), n))516517def dotproduct(vec1, vec2):518 return sum(map(operator.mul, vec1, vec2))519520def flatten(listOfLists):521 "Flatten one level of nesting"522 return chain.from_iterable(listOfLists)523524def repeatfunc(func, times=None, *args):525 """Повторяет вызовы func с указанными аргументами.526527 Пример: repeatfunc(random.random)528 """529 if times is None:530 return starmap(func, repeat(args))531 return starmap(func, repeat(args, times))532533def pairwise(iterable):534 "s -> (s0,s1), (s1,s2), (s2, s3), ..."535 a, b = tee(iterable)536 next(b, None)537 return zip(a, b)538539def grouper(n, iterable, fillvalue=None):540 "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"541 args = [iter(iterable)] * n542 return zip_longest(*args, fillvalue=fillvalue)543544def roundrobin(*iterables):545 "roundrobin('ABC', 'D', 'EF') --> A D E B F C"546 # Автор рецепта – Джордж Саккис547 pending = len(iterables)548 nexts = cycle(iter(it).__next__ for it in iterables)549 while pending:550 try:551 for next in nexts:552 yield next()553 except StopIteration:554 pending -= 1555 nexts = cycle(islice(nexts, pending))556557def powerset(iterable):558 "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"559 s = list(iterable)560 return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))561562def unique_everseen(iterable, key=None):563 "List unique elements, preserving order. Remember all elements ever seen."564 # unique_everseen('AAAABBBCCDAABBB') --> A B C D565 # unique_everseen('ABBCcAD', str.lower) --> A B C D566 seen = set()567 seen_add = seen.add568 if key is None:569 for element in filterfalse(seen.__contains__, iterable):570 seen_add(element)571 yield element572 else:573 for element in iterable:574 k = key(element)575 if k not in seen:576 seen_add(k)577 yield element578579def unique_justseen(iterable, key=None):580 "List unique elements, preserving order. Remember only the element just seen."581 # unique_justseen('AAAABBBCCDAABBB') --> A B C D A B582 # unique_justseen('ABBCcAD', str.lower) --> A B C A D583 return map(next, map(itemgetter(1), groupby(iterable, key)))584585def iter_except(func, exception, first=None):586 """ Повторно вызывает функцию до возникновения исключения.587588 Преобразует интерфейс вызова до исключения в интерфейс итератора.589 Подобно __builtin__.iter(func, sentinel), но использует исключение вместо этого590 сигнального значения для завершения цикла.591592 Примеры:593 iter_except(functools.partial(heappop, h), IndexError) # итератор очереди с приоритетом594 iter_except(d.popitem, KeyError) # итератор словаря без блокировки595 iter_except(d.popleft, IndexError) # итератор дека без блокировки596 iter_except(q.get_nowait, Queue.Empty) # цикл по очереди производителя597 iter_except(s.pop, KeyError) # итератор множества без блокировки598599 """600 try:601 if first is not None:602 yield first() # Для API баз данных, требующих первоначального приведения к db.first()603 while 1:604 yield func()605 except exception:606 pass607608def random_product(*args, repeat=1):609 "Random selection from itertools.product(*args, **kwds)"610 pools = [tuple(pool) for pool in args] * repeat611 return tuple(random.choice(pool) for pool in pools)612613def random_permutation(iterable, r=None):614 "Random selection from itertools.permutations(iterable, r)"615 pool = tuple(iterable)616 r = len(pool) if r is None else r617 return tuple(random.sample(pool, r))618619def random_combination(iterable, r):620 "Random selection from itertools.combinations(iterable, r)"621 pool = tuple(iterable)622 n = len(pool)623 indices = sorted(random.sample(range(n), r))624 return tuple(pool[i] for i in indices)625626def random_combination_with_replacement(iterable, r):627 "Random selection from itertools.combinations_with_replacement(iterable, r)"628 pool = tuple(iterable)629 n = len(pool)630 indices = sorted(random.randrange(n) for i in range(r))631 return tuple(pool[i] for i in indices)632```633634Обратите внимание: многие из приведённых выше рецептов можно оптимизировать, заменив глобальные поиски локальными переменными, определёнными как значения по умолчанию. Например, рецепт *dotproduct* можно записать так:635636```python637def dotproduct(vec1, vec2, sum=sum, map=map, mul=operator.mul):638 return sum(map(mul, vec1, vec2))639```640