itertools.md
1> **Источник:** https://python-all.ru/3.2/library/itertools.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 9.1. [`itertools`](https://python-all.ru/3.2/library/itertools.html#module-itertools) – Функции, создающие итераторы для эффективных циклов89Этот модуль реализует ряд строительных блоков [*итераторов*](https://python-all.ru/3.2/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.2/library/functions.html#map) и [`count()`](https://python-all.ru/3.2/library/itertools.html#itertools.count), чтобы получить `map(f, count())`.1415Эти инструменты и их встроенные аналоги также хорошо работают с высокоскоростными функциями из модуля [`operator`](https://python-all.ru/3.2/library/operator.html#module-operator). Например, оператор умножения можно применить к двум векторам, чтобы вычислить эффективное скалярное произведение: `sum(map(operator.mul, vector1, vector2))`.1617**Бесконечные итераторы:**1819| Итератор | Аргументы | Результаты | Пример |20| --- | --- | --- | --- |21| [`count()`](https://python-all.ru/3.2/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.2/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.2/library/itertools.html#itertools.repeat) | elem \[,n\] | elem, elem, elem, ... бесконечно или до n раз | `repeat(10, 3) --> 10 10 10` |2425**Итераторы, завершающиеся по кратчайшей входной последовательности:**2627| Итератор | Аргументы | Результаты | Пример |28| --- | --- | --- | --- |29| [`accumulate()`](https://python-all.ru/3.2/library/itertools.html#itertools.accumulate) | p | p0, p0+p1, p0+p1+p2, ... | `accumulate([1,2,3,4,5]) --> 1 3 6 10 15` |30| [`chain()`](https://python-all.ru/3.2/library/itertools.html#itertools.chain) | p, q, ... | p0, p1, ... plast, q0, q1, ... | `chain('ABC', 'DEF') --> A B C D E F` |31| [`compress()`](https://python-all.ru/3.2/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` |32| [`dropwhile()`](https://python-all.ru/3.2/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` |33| [`filterfalse()`](https://python-all.ru/3.2/library/itertools.html#itertools.filterfalse) | pred, seq | элементы seq, для которых pred(elem) равно False | `filterfalse(lambda x: x%2, range(10)) --> 0 2 4 6 8` |34| [`groupby()`](https://python-all.ru/3.2/library/itertools.html#itertools.groupby) | iterable\[, keyfunc\] | под-итераторы, сгруппированные по значению keyfunc(v) | |35| [`islice()`](https://python-all.ru/3.2/library/itertools.html#itertools.islice) | seq, \[start,\] stop \[, step\] | элементы из seq\[start:stop:step\] | `islice('ABCDEFG', 2, None) --> C D E F G` |36| [`starmap()`](https://python-all.ru/3.2/library/itertools.html#itertools.starmap) | func, seq | func(\*seq\[0\]), func(\*seq\[1\]), ... | `starmap(pow, [(2,5), (3,2), (10,3)]) --> 32 9 1000` |37| [`takewhile()`](https://python-all.ru/3.2/library/itertools.html#itertools.takewhile) | pred, seq | seq\[0\], seq\[1\], пока pred не вернёт ложь | `takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4` |38| [`tee()`](https://python-all.ru/3.2/library/itertools.html#itertools.tee) | it, n | it1, it2 , ... itn делит один итератор на n | |39| [`zip_longest()`](https://python-all.ru/3.2/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-` |4041**Комбинаторные генераторы:**4243| Итератор | Аргументы | Результаты |44| --- | --- | --- |45| [`product()`](https://python-all.ru/3.2/library/itertools.html#itertools.product) | p, q, ... \[repeat=1\] | декартово произведение, эквивалентно вложенному циклу for |46| [`permutations()`](https://python-all.ru/3.2/library/itertools.html#itertools.permutations) | p\[, r\] | кортежи длиной r, все возможные перестановки, без повторяющихся элементов |47| [`combinations()`](https://python-all.ru/3.2/library/itertools.html#itertools.combinations) | p, r | кортежи длиной r, в отсортированном порядке, без повторяющихся элементов |48| [`combinations_with_replacement()`](https://python-all.ru/3.2/library/itertools.html#itertools.combinations_with_replacement) | p, r | кортежи длиной r, в отсортированном порядке, с повторяющимися элементами |49| `product('ABCD', repeat=2)` | | `AA AB AC AD BA BB BC BD CA CB CC CD DA DB DC DD` |50| `permutations('ABCD', 2)` | | `AB AC AD BA BC BD CA CB CD DA DB DC` |51| `combinations('ABCD', 2)` | | `AB AC AD BC BD CD` |52| `combinations_with_replacement('ABCD', 2)` | | `AA AB AC AD BB BC BD CC CD DD` |5354## 9.1.1. Функции для работы с итераторами5556Следующие функции модуля создают и возвращают итераторы. Некоторые из них порождают потоки бесконечной длины, поэтому обращаться к ним следует только с помощью функций или циклов, которые обрывают поток.5758#### `itertools.accumulate(iterable)`5960Создаёт итератор, возвращающий накопленные суммы. Элементы могут быть любого складываемого типа, включая `Decimal` или `Fraction`. Эквивалентно:6162```python63def accumulate(iterable):64 'Return running totals'65 # accumulate([1,2,3,4,5]) --> 1 3 6 10 1566 it = iter(iterable)67 total = next(it)68 yield total69 for element in it:70 total = total + element71 yield total72```7374Новое в версии 3.2.7576#### `itertools.chain(*iterables)`7778Создаёт итератор, возвращающий элементы из первого итерируемого объекта до его исчерпания, затем переходит к следующему и так далее, пока все итерируемые объекты не будут исчерпаны. Используется для обработки последовательных последовательностей как одной последовательности. Эквивалентно:7980```python81def chain(*iterables):82 # chain('ABC', 'DEF') --> A B C D E F83 for it in iterables:84 for element in it:85 yield element86```8788#### `classmethod chain.from_iterable(iterable)`8990Альтернативный конструктор для [`chain()`](https://python-all.ru/3.2/library/itertools.html#itertools.chain). Получает цепочку входных данных из одного итерируемого аргумента, который вычисляется лениво. Эквивалентно:9192```python93@classmethod94def from_iterable(iterables):95 # chain.from_iterable(['ABC', 'DEF']) --> A B C D E F96 for it in iterables:97 for element in it:98 yield element99```100101#### `itertools.combinations(iterable, r)`102103Возвращает подпоследовательности элементов длины *r* из входного *iterable*.104105Комбинации выдаются в лексикографическом порядке. Таким образом, если входной *итерируемый объект* отсортирован, кортежи комбинаций будут созданы в отсортированном порядке.106107Элементы считаются уникальными на основе их позиции, а не значения. Поэтому если входные элементы уникальны, то в каждой комбинации не будет повторяющихся значений.108109Эквивалентно следующему:110111```python112def combinations(iterable, r):113 # combinations('ABCD', 2) --> AB AC AD BC BD CD114 # combinations(range(4), 3) --> 012 013 023 123115 pool = tuple(iterable)116 n = len(pool)117 if r > n:118 return119 indices = list(range(r))120 yield tuple(pool[i] for i in indices)121 while True:122 for i in reversed(range(r)):123 if indices[i] != i + n - r:124 break125 else:126 return127 indices[i] += 1128 for j in range(i+1, r):129 indices[j] = indices[j-1] + 1130 yield tuple(pool[i] for i in indices)131```132133Код для [`combinations()`](https://python-all.ru/3.2/library/itertools.html#itertools.combinations) также можно выразить как подпоследовательность [`permutations()`](https://python-all.ru/3.2/library/itertools.html#itertools.permutations) после фильтрации записей, в которых элементы не отсортированы (согласно их позиции во входном пуле):134135```python136def combinations(iterable, r):137 pool = tuple(iterable)138 n = len(pool)139 for indices in permutations(range(n), r):140 if sorted(indices) == list(indices):141 yield tuple(pool[i] for i in indices)142```143144Количество возвращаемых элементов равно `n! / r! / (n-r)!`, когда `0 <= r <= n`, или нулю, когда `r > n`.145146#### `itertools.combinations_with_replacement(iterable, r)`147148Возвращает подпоследовательности элементов длины *r* из входного *iterable*, допуская повторение отдельных элементов.149150Комбинации выдаются в лексикографическом порядке. Таким образом, если входной *итерируемый объект* отсортирован, кортежи комбинаций будут созданы в отсортированном порядке.151152Элементы считаются уникальными по их позиции, а не по значению. Поэтому если входные элементы уникальны, сгенерированные комбинации также будут уникальны.153154Эквивалентно следующему:155156```python157def combinations_with_replacement(iterable, r):158 # combinations_with_replacement('ABC', 2) --> AA AB AC BB BC CC159 pool = tuple(iterable)160 n = len(pool)161 if not n and r:162 return163 indices = [0] * r164 yield tuple(pool[i] for i in indices)165 while True:166 for i in reversed(range(r)):167 if indices[i] != n - 1:168 break169 else:170 return171 indices[i:] = [indices[i] + 1] * (r - i)172 yield tuple(pool[i] for i in indices)173```174175Код для [`combinations_with_replacement()`](https://python-all.ru/3.2/library/itertools.html#itertools.combinations_with_replacement) также можно выразить как подпоследовательность [`product()`](https://python-all.ru/3.2/library/itertools.html#itertools.product) после фильтрации записей, в которых элементы не отсортированы (согласно их позиции во входном пуле):176177```python178def combinations_with_replacement(iterable, r):179 pool = tuple(iterable)180 n = len(pool)181 for indices in product(range(n), repeat=r):182 if sorted(indices) == list(indices):183 yield tuple(pool[i] for i in indices)184```185186Количество возвращаемых элементов равно `(n+r-1)! / r! / (n-1)!`, когда `n > 0`.187188Новое в версии 3.1.189190#### `itertools.compress(data, selectors)`191192Создаёт итератор, который фильтрует элементы из *data*, возвращая только те, для которых соответствующий элемент в *selectors* вычисляется как `True`. Останавливается, когда исчерпан либо *data*, либо *selectors*. Эквивалентно:193194```python195def compress(data, selectors):196 # compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F197 return (d for d, s in zip(data, selectors) if s)198```199200Новое в версии 3.1.201202#### `itertools.count(start=0, step=1)`203204Создаёт итератор, возвращающий равномерно расположенные значения, начиная с *n*. Часто используется как аргумент для [`map()`](https://python-all.ru/3.2/library/functions.html#map) для генерации последовательных точек данных. Также используется с [`zip()`](https://python-all.ru/3.2/library/functions.html#zip) для добавления порядковых номеров. Эквивалентно:205206```python207def count(start=0, step=1):208 # count(10) --> 10 11 12 13 14 ...209 # count(2.5, 0.5) -> 2.5 3.0 3.5 ...210 n = start211 while True:212 yield n213 n += step214```215216При подсчёте с числами с плавающей запятой иногда можно добиться лучшей точности, заменив его на мультипликативный код, например: `(start + step * i for i in count())`.217218Изменено в версии 3.1: Добавлен аргумент *step* и разрешены нецелочисленные аргументы.219220#### `itertools.cycle(iterable)`221222Создаёт итератор, возвращающий элементы из итерируемого объекта и сохраняющий копию каждого. Когда итерируемый объект исчерпан, возвращает элементы из сохранённой копии. Повторяется бесконечно. Эквивалентно:223224```python225def cycle(iterable):226 # cycle('ABCD') --> A B C D A B C D A B C D ...227 saved = []228 for element in iterable:229 yield element230 saved.append(element)231 while saved:232 for element in saved:233 yield element234```235236Примечание: этот элемент набора инструментов может потребовать значительного дополнительного хранилища (в зависимости от длины итерабельного объекта).237238#### `itertools.dropwhile(predicate, iterable)`239240Создаёт итератор, который отбрасывает элементы из итерируемого объекта, пока предикат истинен; после этого возвращает каждый элемент. Обратите внимание: итератор не выдаёт *никакого* вывода, пока предикат не станет ложным, поэтому время запуска может быть значительным. Эквивалентно:241242```python243def dropwhile(predicate, iterable):244 # dropwhile(lambda x: x<5, [1,4,6,4,1]) --> 6 4 1245 iterable = iter(iterable)246 for x in iterable:247 if not predicate(x):248 yield x249 break250 for x in iterable:251 yield x252```253254#### `itertools.filterfalse(predicate, iterable)`255256Создаёт итератор, который фильтрует элементы из итерируемого объекта, возвращая только те, для которых предикат равен `False`. Если *predicate* равен `None`, возвращает элементы, которые являются ложными. Эквивалентно.257258```python259def filterfalse(predicate, iterable):260 # filterfalse(lambda x: x%2, range(10)) --> 0 2 4 6 8261 if predicate is None:262 predicate = bool263 for x in iterable:264 if not predicate(x):265 yield x266```267268#### `itertools.groupby(iterable, key=None)`269270Создаёт итератор, который возвращает последовательные ключи и группы из *iterable*. *key* – это функция, вычисляющая ключевое значение для каждого элемента. Если он не указан или равен `None`, то *key* по умолчанию принимает тождественную функцию и возвращает элемент без изменений. Обычно iterable должен быть отсортирован по той же ключевой функции.271272Работа [`groupby()`](https://python-all.ru/3.2/library/itertools.html#itertools.groupby) похожа на фильтр `uniq` в Unix. Она создаёт разрыв или новую группу каждый раз, когда значение ключевой функции меняется (именно поэтому данные обычно необходимо отсортировать с помощью той же ключевой функции). Такое поведение отличается от SQL’s GROUP BY, которое объединяет общие элементы независимо от их порядка во входных данных.273274Возвращаемая группа сама является итератором, который использует тот же исходный итератор, что и [`groupby()`](https://python-all.ru/3.2/library/itertools.html#itertools.groupby). Поскольку источник общий, когда [`groupby()`](https://python-all.ru/3.2/library/itertools.html#itertools.groupby) объект продвигается, предыдущая группа перестаёт быть видимой. Поэтому, если эти данные потребуются позже, их следует сохранить в виде списка:275276```python277groups = []278uniquekeys = []279data = sorted(data, key=keyfunc)280for k, g in groupby(data, keyfunc):281 groups.append(list(g)) # Сохранить групповой итератор как список282 uniquekeys.append(k)283```284285[`groupby()`](https://python-all.ru/3.2/library/itertools.html#itertools.groupby) эквивалентен следующему:286287```python288class groupby:289 # [k for k, g in groupby('AAAABBBCCDAABBB')] --> A B C D A B290 # [list(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D291 def __init__(self, iterable, key=None):292 if key is None:293 key = lambda x: x294 self.keyfunc = key295 self.it = iter(iterable)296 self.tgtkey = self.currkey = self.currvalue = object()297 def __iter__(self):298 return self299 def __next__(self):300 while self.currkey == self.tgtkey:301 self.currvalue = next(self.it) # Выход при StopIteration302 self.currkey = self.keyfunc(self.currvalue)303 self.tgtkey = self.currkey304 return (self.currkey, self._grouper(self.tgtkey))305 def _grouper(self, tgtkey):306 while self.currkey == tgtkey:307 yield self.currvalue308 self.currvalue = next(self.it) # Выход при StopIteration309 self.currkey = self.keyfunc(self.currvalue)310```311312#### `itertools.islice(iterable, stop)`313314#### `itertools.islice(iterable, start, stop[, step])`315316Создаёт итератор, который возвращает выбранные элементы из iterable. Если *start* не равен нулю, то элементы из iterable пропускаются до тех пор, пока не будет достигнут start. После этого элементы возвращаются подряд, если только *step* не больше единицы, что приводит к пропуску элементов. Если *stop* равен `None`, то итерация продолжается, пока итератор не исчерпается; в противном случае она останавливается на указанной позиции. В отличие от обычного среза, [`islice()`](https://python-all.ru/3.2/library/itertools.html#itertools.islice) не поддерживает отрицательные значения для *start*, *stop* или *step*. Может использоваться для извлечения связанных полей из данных, у которых внутренняя структура была сплющена (например, в многострочном отчёте поле имени может располагаться на каждой третьей строке). Эквивалентен:317318```python319def islice(iterable, *args):320 # islice('ABCDEFG', 2) --> A B321 # islice('ABCDEFG', 2, 4) --> C D322 # islice('ABCDEFG', 2, None) --> C D E F G323 # islice('ABCDEFG', 0, None, 2) --> A C E G324 s = slice(*args)325 it = iter(range(s.start or 0, s.stop or sys.maxsize, s.step or 1))326 nexti = next(it)327 for i, element in enumerate(iterable):328 if i == nexti:329 yield element330 nexti = next(it)331```332333Если *start* равен `None`, то итерация начинается с нуля. Если *step* равен `None`, то шаг по умолчанию равен единице.334335#### `itertools.permutations(iterable, r=None)`336337Возвращает последовательные перестановки длины *r* элементов из *iterable*.338339Если *r* не указан или равен `None`, то *r* по умолчанию принимает длину *iterable* и генерируются все возможные перестановки полной длины.340341Перестановки выдаются в лексикографическом порядке. Таким образом, если входной *итерируемый объект* отсортирован, кортежи перестановок будут созданы в отсортированном порядке.342343Элементы считаются уникальными на основе их позиции, а не значения. Поэтому если входные элементы уникальны, то в каждой перестановке не будет повторяющихся значений.344345Эквивалентно следующему:346347```python348def permutations(iterable, r=None):349 # permutations('ABCD', 2) --> AB AC AD BA BC BD CA CB CD DA DB DC350 # permutations(range(3)) --> 012 021 102 120 201 210351 pool = tuple(iterable)352 n = len(pool)353 r = n if r is None else r354 if r > n:355 return356 indices = list(range(n))357 cycles = list(range(n, n-r, -1))358 yield tuple(pool[i] for i in indices[:r])359 while n:360 for i in reversed(range(r)):361 cycles[i] -= 1362 if cycles[i] == 0:363 indices[i:] = indices[i+1:] + indices[i:i+1]364 cycles[i] = n - i365 else:366 j = cycles[i]367 indices[i], indices[-j] = indices[-j], indices[i]368 yield tuple(pool[i] for i in indices[:r])369 break370 else:371 return372```373374Код для [`permutations()`](https://python-all.ru/3.2/library/itertools.html#itertools.permutations) можно также выразить как подпоследовательность [`product()`](https://python-all.ru/3.2/library/itertools.html#itertools.product), отфильтрованную для исключения записей с повторяющимися элементами (тех, что находятся на одной и той же позиции во входном пуле):375376```python377def permutations(iterable, r=None):378 pool = tuple(iterable)379 n = len(pool)380 r = n if r is None else r381 for indices in product(range(n), repeat=r):382 if len(set(indices)) == r:383 yield tuple(pool[i] for i in indices)384```385386Количество возвращаемых элементов равно `n! / (n-r)!`, когда `0 <= r <= n` или нулю, когда `r > n`.387388#### `itertools.product(*iterables, repeat=1)`389390Декартово произведение входных итерируемых объектов.391392Эквивалентно вложенным циклам for в генераторном выражении. Например, `product(A, B)` возвращает то же, что и `((x,y) for x in A for y in B)`.393394Вложенные циклы работают как одометр: самый правый элемент увеличивается на каждой итерации. Этот шаблон создает лексикографический порядок, так что если входные итерируемые объекты отсортированы, кортежи произведения выдаются в отсортированном порядке.395396Чтобы вычислить произведение итератора самого на себя, укажите количество повторений с помощью необязательного именованного аргумента *repeat*. Например, `product(A, repeat=4)` означает то же, что и `product(A, A, A, A)`.397398Эта функция эквивалентна следующему коду, за исключением того, что реальная реализация не создаёт промежуточные результаты в памяти:399400```python401def product(*args, repeat=1):402 # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy403 # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111404 pools = [tuple(pool) for pool in args] * repeat405 result = [[]]406 for pool in pools:407 result = [x+[y] for x in result for y in pool]408 for prod in result:409 yield tuple(prod)410```411412#### `itertools.repeat(object[, times])`413414Создаёт итератор, который снова и снова возвращает *object*. Работает бесконечно, если не указан аргумент *times*. Используется как аргумент для [`map()`](https://python-all.ru/3.2/library/functions.html#map) для неизменяемых параметров вызываемой функции. Также используется с [`zip()`](https://python-all.ru/3.2/library/functions.html#zip) для создания неизменяемой части записи кортежа. Эквивалентен:415416```python417def repeat(object, times=None):418 # repeat(10, 3) --> 10 10 10419 if times is None:420 while True:421 yield object422 else:423 for i in range(times):424 yield object425```426427Обычное применение *repeat* – передача потока постоянных значений в *map* или *zip*:428429```python430>>> list(map(pow, range(10), repeat(2)))431[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]432```433434#### `itertools.starmap(function, iterable)`435436Создаёт итератор, который вычисляет функцию, используя аргументы, полученные из итератора. Используется вместо [`map()`](https://python-all.ru/3.2/library/functions.html#map), когда аргументы уже сгруппированы в кортежи из одного итератора (данные были «предварительно сжаты»). Разница между [`map()`](https://python-all.ru/3.2/library/functions.html#map) и [`starmap()`](https://python-all.ru/3.2/library/itertools.html#itertools.starmap) аналогична различию между `function(a,b)` и `function(*c)`. Эквивалентен:437438```python439def starmap(function, iterable):440 # starmap(pow, [(2,5), (3,2), (10,3)]) --> 32 9 1000441 for args in iterable:442 yield function(*args)443```444445#### `itertools.takewhile(predicate, iterable)`446447Создаёт итератор, который возвращает элементы из итератора, пока предикат истинен. Эквивалентен:448449```python450def takewhile(predicate, iterable):451 # takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4452 for x in iterable:453 if predicate(x):454 yield x455 else:456 break457```458459#### `itertools.tee(iterable, n=2)`460461Возвращает *n* независимых итераторов из одного итератора. Эквивалентен:462463```python464def tee(iterable, n=2):465 it = iter(iterable)466 deques = [collections.deque() for i in range(n)]467 def gen(mydeque):468 while True:469 if not mydeque: # когда локальная deque пуста470 newval = next(it) # извлечь новое значение и471 for d in deques: # загрузить его во все двусторонние очереди472 d.append(newval)473 yield mydeque.popleft()474 return tuple(gen(d) for d in deques)475```476477После того, как [`tee()`](https://python-all.ru/3.2/library/itertools.html#itertools.tee) произвел разделение, исходный *iterable* не должен использоваться где-либо ещё; в противном случае *iterable* может быть продвинут без уведомления объектов tee.478479Этот инструмент итерации может потребовать значительного объёма дополнительной памяти (в зависимости от того, сколько временных данных нужно сохранить). В общем случае, если один итератор использует большую часть или все данные до того, как запускается другой итератор, быстрее использовать [`list()`](https://python-all.ru/3.2/library/functions.html#list) вместо [`tee()`](https://python-all.ru/3.2/library/itertools.html#itertools.tee).480481#### `itertools.zip_longest(*iterables, fillvalue=None)`482483Создаёт итератор, который объединяет элементы из каждого из итераторов. Если итераторы имеют разную длину, отсутствующие значения заполняются с помощью *fillvalue*. Итерация продолжается, пока самый длинный итератор не будет исчерпан. Эквивалентен:484485```python486class ZipExhausted(Exception):487 pass488489def zip_longest(*args, **kwds):490 # zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-491 fillvalue = kwds.get('fillvalue')492 counter = len(args) - 1493 def sentinel():494 nonlocal counter495 if not counter:496 raise ZipExhausted497 counter -= 1498 yield fillvalue499 fillers = repeat(fillvalue)500 iterators = [chain(it, sentinel(), fillers) for it in args]501 try:502 while iterators:503 yield tuple(map(next, iterators))504 except ZipExhausted:505 pass506```507508Если один из итераторов потенциально бесконечен, то функция [`zip_longest()`](https://python-all.ru/3.2/library/itertools.html#itertools.zip_longest) должна быть обёрнута чем-то, что ограничивает количество вызовов (например, [`islice()`](https://python-all.ru/3.2/library/itertools.html#itertools.islice) или [`takewhile()`](https://python-all.ru/3.2/library/itertools.html#itertools.takewhile)). Если не указано, *fillvalue* по умолчанию равен `None`.509510## 9.1.2. Рецепты itertools511512В этом разделе представлены рецепты для создания расширенного набора инструментов с использованием существующих itertools в качестве строительных блоков.513514Расширенные инструменты обеспечивают такую же высокую производительность, как и базовый набор инструментов. Превосходная производительность по памяти достигается за счёт обработки элементов по одному, а не загрузки всего итерируемого объекта в память сразу. Объём кода остаётся небольшим благодаря связыванию инструментов в функциональном стиле, что помогает избавиться от временных переменных. Высокая скорость сохраняется за счёт предпочтения «векторизованных» строительных блоков вместо использования циклов for и [*генераторов*](https://python-all.ru/3.2/glossary.html#term-generator), которые создают накладные расходы интерпретатора.515516```python517def take(n, iterable):518 "Return first n items of the iterable as a list"519 return list(islice(iterable, n))520521def tabulate(function, start=0):522 "Return function(0), function(1), ..."523 return map(function, count(start))524525def consume(iterator, n):526 "Advance the iterator n-steps ahead. If n is none, consume entirely."527 # Используйте функции, потребляющие итераторы на скорости C.528 if n is None:529 # передать весь итератор в deque нулевой длины530 collections.deque(iterator, maxlen=0)531 else:532 # перейти к пустому срезу начиная с позиции n533 next(islice(iterator, n, n), None)534535def nth(iterable, n, default=None):536 "Returns the nth item or a default value"537 return next(islice(iterable, n, None), default)538539def quantify(iterable, pred=bool):540 "Count how many times the predicate is true"541 return sum(map(pred, iterable))542543def padnone(iterable):544 """Возвращает элементы последовательности, а затем бесконечно возвращает None.545546 Полезно для эмуляции поведения встроенной функции map().547 """548 return chain(iterable, repeat(None))549550def ncycles(iterable, n):551 "Returns the sequence elements n times"552 return chain.from_iterable(repeat(tuple(iterable), n))553554def dotproduct(vec1, vec2):555 return sum(map(operator.mul, vec1, vec2))556557def flatten(listOfLists):558 "Flatten one level of nesting"559 return chain.from_iterable(listOfLists)560561def repeatfunc(func, times=None, *args):562 """Повторяет вызовы func с указанными аргументами.563564 Пример: repeatfunc(random.random)565 """566 if times is None:567 return starmap(func, repeat(args))568 return starmap(func, repeat(args, times))569570def pairwise(iterable):571 "s -> (s0,s1), (s1,s2), (s2, s3), ..."572 a, b = tee(iterable)573 next(b, None)574 return zip(a, b)575576def grouper(n, iterable, fillvalue=None):577 "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"578 args = [iter(iterable)] * n579 return zip_longest(*args, fillvalue=fillvalue)580581def roundrobin(*iterables):582 "roundrobin('ABC', 'D', 'EF') --> A D E B F C"583 # Автор рецепта – Джордж Саккис584 pending = len(iterables)585 nexts = cycle(iter(it).__next__ for it in iterables)586 while pending:587 try:588 for next in nexts:589 yield next()590 except StopIteration:591 pending -= 1592 nexts = cycle(islice(nexts, pending))593594def partition(pred, iterable):595 'Use a predicate to partition entries into false entries and true entries'596 # partition(is_odd, range(10)) --> 0 2 4 6 8 и 1 3 5 7 9597 t1, t2 = tee(iterable)598 return filterfalse(pred, t1), filter(pred, t2)599600def powerset(iterable):601 "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"602 s = list(iterable)603 return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))604605def unique_everseen(iterable, key=None):606 "List unique elements, preserving order. Remember all elements ever seen."607 # unique_everseen('AAAABBBCCDAABBB') --> A B C D608 # unique_everseen('ABBCcAD', str.lower) --> A B C D609 seen = set()610 seen_add = seen.add611 if key is None:612 for element in filterfalse(seen.__contains__, iterable):613 seen_add(element)614 yield element615 else:616 for element in iterable:617 k = key(element)618 if k not in seen:619 seen_add(k)620 yield element621622def unique_justseen(iterable, key=None):623 "List unique elements, preserving order. Remember only the element just seen."624 # unique_justseen('AAAABBBCCDAABBB') --> A B C D A B625 # unique_justseen('ABBCcAD', str.lower) --> A B C A D626 return map(next, map(itemgetter(1), groupby(iterable, key)))627628def iter_except(func, exception, first=None):629 """ Повторно вызывает функцию до возникновения исключения.630631 Преобразует интерфейс вызова до исключения в интерфейс итератора.632 Подобно __builtin__.iter(func, sentinel), но использует исключение вместо этого633 сигнального значения для завершения цикла.634635 Примеры:636 iter_except(functools.partial(heappop, h), IndexError) # итератор очереди с приоритетом637 iter_except(d.popitem, KeyError) # итератор словаря без блокировки638 iter_except(d.popleft, IndexError) # итератор дека без блокировки639 iter_except(q.get_nowait, Queue.Empty) # цикл по очереди производителя640 iter_except(s.pop, KeyError) # итератор множества без блокировки641642 """643 try:644 if first is not None:645 yield first() # Для API баз данных, требующих первоначального приведения к db.first()646 while 1:647 yield func()648 except exception:649 pass650651def random_product(*args, repeat=1):652 "Random selection from itertools.product(*args, **kwds)"653 pools = [tuple(pool) for pool in args] * repeat654 return tuple(random.choice(pool) for pool in pools)655656def random_permutation(iterable, r=None):657 "Random selection from itertools.permutations(iterable, r)"658 pool = tuple(iterable)659 r = len(pool) if r is None else r660 return tuple(random.sample(pool, r))661662def random_combination(iterable, r):663 "Random selection from itertools.combinations(iterable, r)"664 pool = tuple(iterable)665 n = len(pool)666 indices = sorted(random.sample(range(n), r))667 return tuple(pool[i] for i in indices)668669def random_combination_with_replacement(iterable, r):670 "Random selection from itertools.combinations_with_replacement(iterable, r)"671 pool = tuple(iterable)672 n = len(pool)673 indices = sorted(random.randrange(n) for i in range(r))674 return tuple(pool[i] for i in indices)675```676677Обратите внимание: многие из приведённых выше рецептов можно оптимизировать, заменив глобальные поиски локальными переменными, определёнными как значения по умолчанию. Например, рецепт *dotproduct* можно записать так:678679```python680def dotproduct(vec1, vec2, sum=sum, map=map, mul=operator.mul):681 return sum(map(mul, vec1, vec2))682```683