Использование модуля itertools в Python
В данном руководстве мы рассмотрим использование основных методов count(), cycle() и chain() стандартной библиотеки itertools в Python.
Введение
В Python есть множество встроенных инструментов, которые позволяют нам выполнять итерации и преобразовывать данные. Отличным примером является модуль itertools, который предлагает несколько удобных функций итерации. Каждая из этих функций построения итераторов (они генерируют итераторы) может использоваться самостоятельно или комбинироваться.
Модуль был вдохновлен функциональными языками, такими как APL, Haskell и SPL, а элементы внутри itertools образуют алгебру итераторов Python.
Итератор и итерабельность
Прежде чем мы погрузимся в итерацию, давайте сначала определим различие между двумя важными терминами: iterable и iterator.
Итерабельность — это объект, по которому можно выполнять итерации. При использовании функции iter() создается итератор. Вообще говоря, большинство последовательностей являются итерируемыми, например, списки, кортежи, строки и т.д.
Итератор — это также объект, который используется для итерации по итерируемой последовательности. Итератор также может итерировать сам себя. Это делается с помощью метода next(), передавая итератор, который мы пытаемся обойти.
Метод next() возвращает следующий элемент объекта итератора. Итератор может быть сгенерирован из итерабельного объекта (с помощью функции iter()):
Теперь давайте обратимся к элементу next() (начиная с первого), используя наш итератор:
Это практически то, что происходит под капотом цикла for — он вызывает функцию iter() на коллекции, над которой вы итерируетесь, и после этого к элементу next() обращаются n раз.
В этой статье мы рассмотрим несколько инструментов итерации в Python:
Функция count()
Функция count(start, step) создает итератор и используется для генерации равномерно расположенных значений, где промежуток между ними определяется аргументом step. Аргумент start определяет начальное значение итератора — по умолчанию это значение равно start=0 и step=1.
Без условия прерывания функция count() будет продолжать считать бесконечно (в системе с неограниченной памятью):
Примечание: Подобное использование count() необычно. Обычно ее используют в цепочке с другими методами, такими как zip(), map() или imap().
Здесь итератор итерирует сам себя, печатая значения с шагом 10:
Учитывая ее генеративный характер, эта функция чаще всего используется вместе с другими функциями, которые ожидают новых или генерирующих последовательностей.
Например, при использовании функции zip() для сшивания нескольких элементов списка, вы можете захотеть аннотировать их с помощью позиционного индекса. В процессе выполнения функции zip() мы будем использовать функцию count() для генерации значений для этих индексов:
Функция cycle()
Функция cycle() принимает итератор и генерирует итератор, который содержит все элементы итератора. Помимо этих элементов, он содержит копию каждого элемента.
Как только мы дойдем до конца элементов, мы начнем итерацию по копиям. Во время перебора копий создаются новые копии. Как только первый набор копий заканчивается, мы начинаем итерацию по новому набору.
Этот процесс повторяется бесконечно.
Примечание: Учитывая этот факт, использование функции cycle(), особенно для длинных последовательностей, отнимает много памяти. Остерегайтесь бесконечной, рекурсивной логики создания, так как у вас легко закончится память для размещения всего этого:
Пока мы не завершим программу или не закончится память. Учитывая это, необходимо всегда иметь условие выхода/завершения для функции cycle().
Учитывая тот факт, что функция cycle() может перебирать любые итерации, мы можем легко применить ее к строкам и кортежам.
Функция chain()
Функция chain() используется для объединения в цепочку нескольких итераторов, создавая итератор, который обходит их последовательно, один за другим:
Здесь у нас есть четыре различных типа итерабельных элементов, каждый из которых соединяется в цепочку.
Несмотря на то, что [«Egor», «Denis», «Oleg», «Anton», «George»] — это список строк, chain() рассматривает его как список и просто соединяет его элементы в цепочку без вызова последующей chain() для каждой из строк. С другой стороны, «Test1» разбивается на составляющие ее символы.
Первое может быть достигнуто с помощью другого метода, производного от функции chain() — chain.from_iterable():
Функция chain() ведет себя так же, как мы наблюдали ранее — она выстраивает элементы в цепочку, как они есть. С другой стороны, метод chain.from_iterable() рассматривает каждый элемент как итерабельность и возвращает его составные элементы вместе с другими элементами, разбитыми таким же образом:
Обычно вы используете chain.from_iterable() для вычисления суммы цифр, содержащихся в нескольких коллекциях, которые вы сначала объединяете в цепочку, а затем вычисляете для них sum():
Каждый элемент коллекции example_list — это еще один список. Поскольку списки итерируемы, вызов chain.from_iterable() разбивает их на один список, содержащий элементы из [1..9], после чего мы вычисляем их sum() и выводим результат:
Заключение
Модуль itertools знакомит нас с несколькими полезными удобными функциями для работы с итерациями и итерациями.
Многие из них можно использовать как самостоятельные функции, но чаще всего они используются в связке с другими функциями для преобразования данных.
Composable cycles¶
cycler API¶
Create a new Cycler object from a single positional argument, a pair of positional arguments, or the combination of keyword arguments.
Cycler Usage¶
A single entry Cycler object can be used to easily cycle over a single style. To create the Cycler use the cycler() function to link a key/style/kwarg to series of values. The key must be hashable (as it will eventually be used as the key in a dict ).
The Cycler knows it’s length and keys:
Iterating over this object will yield a series of dict objects keyed on the label
Cycler objects can be passed as the argument to cycler() which returns a new Cycler with a new label, but the same values.
Iterating over a Cycler results in the finite list of entries, to get an infinite cycle, call the Cycler object (a-la a generator)
Composition¶
A single Cycler can just as easily be replaced by a single for loop. The power of Cycler objects is that they can be composed to easily create complex multi-key cycles.
Addition¶
Equal length Cycler s with different keys can be added to get the ‘inner’ product of two cycles
The result has the same length and has keys which are the union of the two input Cycler ’s.
and iterating over the result is the zip of the two input cycles
As with arithmetic, addition is commutative
For convenience, the cycler() function can have multiple key-value pairs and will automatically compose them into a single Cycler via addition
Multiplication¶
Any pair of Cycler can be multiplied
which gives the ‘outer product’ of the two cycles (same as itertools.product() )
Note that unlike addition, multiplication is not commutative (like matrices)
Integer Multiplication¶
Cycler s can also be multiplied by integer values to increase the length.
Concatenation¶
Cycler objects can be concatenated either via the Cycler.concat() method
or the top-level concat() function
Slicing¶
Cycles can be sliced with slice objects
Inspecting the Cycler ¶
To inspect the values of the transposed Cycler use the Cycler.by_key method:
This dict can be mutated and used to create a new Cycler with the updated values
Examples¶
We can use Cycler instances to cycle over one or more kwarg to plot :
Persistent Cycles¶
It can be useful to associate a given label with a style via dictionary lookup and to dynamically generate that mapping. This can easily be accomplished using a defaultdict
To get a finite set of styles
This can be helpful when plotting complex data which has both a classification and a label
which will result in every data with the same group being plotted with the same style.
Exceptions¶
A ValueError is raised if unequal length Cycler s are added together
or if two cycles which have overlapping keys are composed
Motivation¶
When plotting more than one line it is common to want to be able to cycle over one or more artist styles. For simple cases than can be done with out too much trouble:
However, if you want to do something more complicated:
the plotting logic can quickly become very involved. To address this and allow easy cycling over arbitrary kwargs the Cycler class, a composable kwarg iterator, was developed.
Itertools в Python
Модуль itertools стандартизирует основной набор быстрых эффективных по памяти инструментов, которые полезны сами по себе или в связке с другими инструментами. Вместе они формируют «алгебру итераторов», которая позволяет лаконично и эффективно создавать специализированные инструменты на чистом Python.
Модуль itertools находится в стандартной библиотеке Python.
Модуль представляет следующие типы итераторов:
Возвращаемый объект также будет итератором. Мы можем проходиться по итератору с помощью:
конвертации в список с помощью list()
Бесконечные итераторы:
Создает итератор, возвращающий элементы из итерируемого объекта и сохраняющий копию каждого из них. Когда итерируемый объект заканчивается, возвращается элемент из сохраненной копии. Работает бесконечно.
Конечные итераторы:
Создает итератор, который возвращает накопленную сумму или накопленный результат других бинарных функций, которые указаны в параметре func.
Обычно количество элементов в выходной итерации совпадает с количеством элементов во входной итерации. Если указывается параметр initial, он также учитывается, поэтому выходная итерация содержит на один элемент больше, чем входная.
functools.reduce() возвращает только конечное накопленное значение для аналогичной функции.
Параметр initial добавлен в Python версии 3.8.
Создает итератор, который возвращает элемент из итерируемого объекта до тех пор, пока он не закончится, а потом переходит к следующему. Он будет рассматривать последовательности, идущие друг за другом, как одну.
Эта функция берет один итерируемый объект в качестве входного аргумента и возвращает «склеенный» итерируемый объект, содержащий все элементы входного. Все элементы, подаваемые на вход, должны быть итерируемыми, иначе выпадет исключение TypeError.
Создает итератор, который фильтрует элементы data, возвращая только те, которые содержат соответствующий элемент в селекторах (selectors), стоящих в True. Прекращает выполнение, когда либо данные, либо селекторы закончились.
Создает итератор, который выбрасывает элементы из итерируемого объекта до тех пор, пока предикат (predicate) имеет значение True, а затем возвращает каждый элемент. Итератор не вернет выходных данных, пока предикат не получит значение False.
Создает итератор, который возвращает элементы из итерируемого объекта до тех пор, пока предикат имеет значение True.
Создает итератор, который фильтрует элементы итерируемого объекта, возвращая только те, для которых предикат имеет значение False. Если предикат равен None, он возвращает элементы, которые стоят в значении False.
Метод filter() возвращает итератор, который содержит элементы итерируемого объекта, для которых функция возвращает True.
Создает итератор, который агрегирует элементы из каждого итерируемого объекта. Если итераторы имеют неравномерную длину, то на место пропущенных значений ставится fillvalue. Итерация будет продолжаться до тех пор, пока не закончится самый длинный итерируемый объект.
В zip() итерация продолжается до тех пор, пока не закончится самый короткий итерируемый объект.
Создает итератор, который вычисляет функцию, получая аргументы из итерируемого объекта. Используется вместо map(), когда параметры аргумента уже сгруппированы в кортежи в одном итерируемом объекте (данные были предварительно сжаты).
Создает итератор, который возвращает выбранные элементы из итерируемого объекта. Если start равен None, то итерация начинается с нуля. Если step равен None, то по умолчанию ему дается значение 1. Если stop равен None, то итерация будет продолжаться, пока элементы в итерируемом объекте не закончатся, если они вообще могут закончиться. В противном случае итератор остановится на определенной позиции. В islice() не поддерживаются отрицательные значения для параметров start, stop и step.
itertools.islice(iterable, start, stop[, step])
Возвращает n независимых итераторов из одного итерируемого объекта.
Создает итератор, который возвращает последовательно ключи и группы из итерируемого объекта.
key – это функция, вычисляющая значение ключа для каждого элемента по умолчанию. Если ключ не указан или в значении None, то по умолчанию ключ является функцией идентификации, которая возвращает элемент без изменений.
Комбинаторные генераторы:
Декартово произведение итерируемых объектов, подаваемых на вход.
Определение декартова произведения: произведение множества X и множества Y – это множество, содержащее все упорядоченные пары (x, y), в которых x принадлежит множеству X, а y принадлежит множеству Y.
Чтобы вычислить произведение итерируемого объекта умноженного самого на себя, нужно указать количество повторений с помощью опционального аргумента с ключевым словом repeat. Например, product(A, repeat=4) – тоже самое, что и product(A, A, A, A).
Возвращает последовательные r перестановок элементов в итерируемом объекте. Если параметр r не указан или стоит в значении None, то по умолчанию r принимает длину итерируемого объекта и генерирует все возможные полноценные перестановки. Кортежи перестановок выдаются в лексикографическим порядке в соответствии с порядком итерации входных данных. Таким образом, если входные данные итерируемого объекта отсортированы, то комбинация кортежей будет выдаваться в отсортированном порядке.
Элементы рассматриваются как уникальные в зависимости от их позиции, а не от их значения. Таким образом, если входные элементы уникальны, то в каждой перестановке не будет повторяющихся значений.
Примечание: в перестановках порядок элементов имеет значение.
Возвращает подпоследовательности длины r из элементов итерируемого объекта, подаваемого на вход.
Комбинация кортежей генерируется в лексикографическом порядке в соответствии с порядком элементов итерируемого объекта на входе. Таким образом, если входной итерируемый объект отсортирован, то комбинация кортежей будет генерироваться в отсортированном порядке.
Лексикографический порядок – способ упорядочивания слов в алфавитном порядке.
Элементы рассматриваются как уникальные в зависимости от их позиции, а не значения. Таким образом, если выходные элементы уникальны, то в каждой комбинации не будет повторяющихся значений.
Возвращает подпоследовательности длины r из элементов итерируемого объекта, подаваемого на вход, при этом отдельные элементы могут повторяться больше одного раза.
itertools.combinations_with_replacement (iterable, r)
Примечание:
1. Используется в качестве аргумента в map() и zip() :
2. Разница между cycle() и repeat() :
cycle() – итерирует один и тот же объект снова и снова;
repeat() – возвращает снова и снова один и тот же объект.
3. Разница между reduce() и itertools.accumulate() :
Возвращает только конечную сумму;
Первый аргумент должен быть функцией, а второй – итерируемым объектом.
Возвращает текущее накопленное значение. Элементы в выходном итерируемом объекте будут равны элементам во входном объекте, если не будет указано начальное значение.
Первый аргумент должен быть итерируемым объектом, а второй – функцией.
4. Разница между filter() и itertools.compress() :
Функция filter() фильтрует заданный итерируемый объект с помощью функции, которая проверяет, стоит каждый элемент в значении True или нет.
Функция compress() фильтрует заданный итерируемый объект на основе соответствующего элемента в параметре селектора. В качестве селектора задается итерируемый объект со значениями True/False.
5. Разница между filter() и itertools.filterfalse() :
filter() : создает итератор из элементов итерируемого объекта, для которых заданная функция возвращает значение True.
filterfalse() : создает итератор из элементов итерируемого объекта, для которых заданная функция возвращает значение False.
6. Разница между zip() и itertools.zip_longest() :
zip() : Итерация продолжается до тех пор, пока не закончится самый короткий итерируемый объект.
zip_longest() : Итерация продолжается до тех пор, пока не закончится самый длинный итерируемый объект.
7. Разница между срезом списка и itertools.islice() :
Срез списка создает новый список;
islice() – возвращает итератор. С помощью итератора мы можем организовать цикл так, как нам удобно.
8. Разница между itertools.permutations() и itertools.combinations() :
itertools.permutations() : Порядок элементов имеет значение;
itertools.combinations() : Порядок элементов не имеет значения.
Комбинации и перестановки не содержат повторяющихся значений.
9. Разница между itertools.combinations() и itertools.combination_swith_replacement :
combinations() : Порядок элементов не имеет значения, и значения не повторяются.
combinations_with_replacement() : Порядок элементов не имеет значения, и значения повторяются.
10. Разница между itertools.takewhile() и itertools.dropwhile() :
takewhile() : Создает итератор, который возвращает элементы из итерируемого объекта, пока предикат находится в значении True.
dropwhile() : Создает итератор, который выбрасывает элементы из итерируемого объекта, пока предикат находится в значении True, а затем возвращает каждый элемент.
Искусство написания циклов на Python
Цикл for — самый базовый инструмент потока управления большинства языков программирования. Например, простой цикл for на C выглядит так:
Не существует более изящного способа написания цикла for на C. В сложных случаях обычно приходится писать уродливые вложенные циклы или задавать множество вспомогательных переменных (например, как i в показанном выше коде).
Эта статья познакомит вас с самыми полезными трюками по написанию циклов на Python. Надеюсь, она поможет вам ощутить красоту этого языка.
Одновременно получаем значения и индексы
Частым примером использования цикла for является получение индексов и значений из списка. Когда я начинал изучать Python, то писал свой код таким образом:
Разумеется, он работал. Но это решение не в стиле Python. Спустя несколько месяцев я узнал стандартный способ реализации в стиле Python:
Как мы видим, встроенная функция enumerate упрощает нам жизнь.
Как избежать вложенных циклов с помощью функции Product
Вложенные циклы — это настоящая головная боль. Они могут снизить читаемость кода и усложнить его понимание. Например, прерывание вложенных циклов обычно реализовать не так просто. Нам нужно знать, где прерван самый внутренний цикл, второй по порядку внутренний цикл, и так далее.
Давайте убедимся в её полезности на простом примере:
Как мы видим, нам требуется три вложенных цикла, чтобы получить из трёх списков три числа, сумма которых равна 2077. Код не очень красив.
Как мы видим, благодаря использованию функции product достаточно всего одного цикла.
Так как функция product генерирует прямое произведение входящих итерируемых данных, она позволяет нам во многих случаях избежать вложенных циклов.
Используем модуль Itertools для написания красивых циклов
Создаём бесконечный цикл
Существует не меньше трёх способов создания бесконечного цикла:
1. При помощи функции count :
3. Через функцию repeat :
Комбинируем несколько итераторов в один
Функция chain() позволяет объединить несколько итераторов в один.
Выделяем соседние дублирующиеся элементы
Функция groupby используется для выделения соседних дублирующихся элементов в итераторе и их соединения.
Как показано выше, соседние одинаковые символы соединены вместе. Более того, мы можем указать функции groupby способ определения идентичности двух элементов:
Самостоятельно настраиваем цикл
Изучив представленные выше примеры, давайте задумаемся о том, почему циклы for в Python настолько гибки и изящны. Насколько я понимаю, это из-за того, что мы можем применять в итераторе цикла for функции. Во всех рассмотренных выше примерах в итераторе всего лишь используются специальные функции. Все трюки имеют одинаковый шаблон:
Сам встроенный модуль itertools всего лишь реализует за нас самые распространённые функции. Если мы забудем функцию или не сможем найти нужную нам, то можем просто написать её самостоятельно. Если быть более точным, то эти функции являются генераторами. Именно поэтому мы можем генерировать с их помощью бесконечные циклы.
По сути, мы можем настроить цикл for под себя, как сделали бы это с настраиваемым генератором.
Давайте рассмотрим простой пример:
Разумеется, этот пример приведён только для объяснения. Существуют и другие способы выполнения тех же действий, например, использование представления списков.
Вывод
Задачу создания циклов на Python можно решать очень гибко и изящно. Чтобы писать удобные и простые циклы, мы можем использовать встроенные инструменты или даже самостоятельно определять генераторы.
На правах рекламы
Надёжный сервер в аренду, создавайте свою конфигурацию в пару кликов и начинайте работать уже через минуту. Всё будет работать без сбоев и с очень высоким uptime!
Модуль Itertools в Python на примерах
Itertool – одна из самых удивительных стандартных библиотек Python 3. В этой библиотеке есть самые крутые функции, можно сказать, что это жемчужина языка программирования Python. Python предоставляет отличную документацию по itertools, но в этом руководстве мы обсудим несколько важных и полезных функций или итераторов itertools.
Ключевым моментом в itertools является то, что функции этой библиотеки используются для создания эффективного и точного кода с эффективным использованием памяти.
Прежде чем изучать Python itertools, вы должны знать итератор и генераторы Python. В этой статье мы опишем itertools как для начинающих, так и для профессионалов.
Что такое itertools в Python?
Python itertools – согласно официальному определению itertools, «это модуль, который реализует ряд строительных блоков итератора, вдохновленных конструкциями из APL, Haskell и SML». Проще говоря, количество итераторов вместе может создать «алгебру итераторов», которая позволяет выполнить сложную задачу. Функции в itertools используются для создания более сложных итераторов. Возьмем пример: встроенная в Python функция zip() принимает любое количество аргументов в качестве итерируемых. Она перебирает кортежи и возвращает соответствующие им элементы.
Функция Python iter() используется для вызова итерируемого объекта и возврата объекта итератора для итеративного объекта.
Функция Python zip() вызывает iter() для каждого своего аргумента, а затем вызывает next(), объединяя результат в кортеж.
Примечание. Если вы используете функции zip() и map(), это означает, что вы уже используете itertools. Вам не нужно импортировать его.
Типы итераторов
В модуле itertools есть разные типы итераторов:
Бесконечные итераторы
В Python любой объект, который может реализовать цикл for, называется итератором. Списки, кортежи, наборы, словари, строки являются примерами итераторов, но итератор может быть бесконечным, и этот тип также называется бесконечным.
Пример – 2: Использование функции next()
Комбинаторные итераторы
Комбинаторные итераторы: сложные комбинаторные конструкции упрощаются рекурсивными генераторами. Перестановки, комбинации и декартовы произведения являются примером комбинаторной конструкции.
В Python существует четыре типа комбинаторных итераторов:
Завершающие итераторы
Завершающие итераторы обычно используются для работы с небольшой входной последовательностью и генерации выходных данных на основе функциональности метода, используемого в итераторе.
Существуют разные типы завершающих итераторов:
В этом руководстве мы обсудили несколько полезных итераторов вместе с itertools.








