10 Python Itertools, которые сделают ваш код аккуратнее, чище и лучше

10 Python Itertools, которые сделают ваш код аккуратнее, чище и лучше

Красота Python заключается в его простоте.

Не только потому, что синтаксис Python элегантен, но и потому, что он имеет множество хорошо спроектированных встроенных модулей, которые помогают нам эффективно реализовывать общие функции.

Модуль itertools, который является хорошим примером, предоставляет нам много мощных инструментов для управления итерируемыми объектами Python в более сокращённом коде.

Делайте больше меньшими средствами. Это то, что вы можете получить от модуля itertools.

1. itertools.product(): хитрый способ избежать вложенных циклов

Когда программа становится всё более и более сложной, вам может понадобиться написать вложенные циклы. В то же время ваш код Python станет некрасивым и нечитаемым:

list_a = [1, 2020, 70] list_b = [2, 4, 7, 2000] list_c = [3, 70, 7] for a in list_a: for b in list_b: for c in list_c: if a + b + c == 2077: print(a, b, c) # 70 2000 7

Как снова сделать приведённый выше код привлекательным?

Функция itertools.product()— ваш друг:

from itertools import product list_a = [1, 2020, 70] list_b = [2, 4, 7, 2000] list_c = [3, 70, 7] for a, b, c in product(list_a, list_b, list_c): if a + b + c == 2077: print(a, b, c) # 70 2000 7

Как показано выше, она возвращает декартово произведение входных итераций, что помогает нам объединить 3 вложенных цикла for в один.

2. itertools.compress(): удобный способ фильтрации данных

Мы можем отфильтровать список элементов через один или несколько циклов наверняка.

Но иногда нам может не понадобиться писать циклы, ведь существует функция, именуемая как itertools.compress().

Функция itertools.compress() возвращает итератор, который фильтрует итерируемый объект на основе значений соответствующей логической маски.

Например, следующий код выбирает истинных лидеров с помощью функции itertools.compress():

import itertools leaders = ['Yang', 'Elon', 'Tim', 'Tom', 'Mark'] selector = [1, 1, 0, 0, 0] print(list(itertools.compress(leaders, selector))) # ['Yang', 'Elon']

Второй аргумент selector работает как маска, мы также можем определить его следующим образом:

selector = [True, True, False, False, False]

3. itertools.groupby(): группировка элементов итерируемого объекта

Функция itertools.groupby() представляет собой удобный способ группировать смежные повторяющиеся элементы итерируемого объекта.

Например, мы можем сгруппировать длинную строку следующим образом:

from itertools import groupby for key, group in groupby('YAaANNGGG'): print(key, list(group)) # Y ['Y'] # A ['A'] # a ['a'] # A ['A'] # N ['N', 'N'] # G ['G', 'G', 'G']

Кроме того, мы можем использовать его второй аргумент, чтобы сообщить функции groupby(), как определить, являются ли два элемента одинаковыми или нет:

from itertools import groupby for key, group in groupby('YAaANNGGG', lambda x: x.upper()): print(key, list(group)) # Y ['Y'] # A ['A', 'a', 'A'] # N ['N', 'N'] # G ['G', 'G', 'G']

4. itertools.combinations(): получение всех комбинаций заданной длины из итерируемого объекта.

Новичку нужно некоторое время, чтобы написать безошибочную функцию для получения всех возможных комбинаций списка.

На самом деле, если он знает функцию itertools.combination(), он может легко найти решение:

import itertools author = ['Y', 'a', 'n', 'g'] result = itertools.combinations(author, 2) for x in result: print(x) # ('Y', 'a') # ('Y', 'n') # ('Y', 'g') # ('a', 'n') # ('a', 'g') # ('n', 'g')

Как показано в приведённой выше программе, функция itertools.combination() имеет два параметра: один — исходный итерируемый объект, а другой — длина подпоследовательностей, которые будут сгенерированы функцией.

5. itertools.permutations(): получить все перестановки заданной длины из итерируемого объекта.

Поскольку есть функция для получения всех комбинаций, конечно, есть ещё одна функция, названная itertools.permutations, для получения всех возможных перестановок:

import itertools author = ['Y', 'a', 'n', 'g'] result = itertools.permutations(author, 2) for x in result: print(x) # ('Y', 'a') # ('Y', 'n') # ('Y', 'g') # ('a', 'Y') # ('a', 'n') # ('a', 'g') # ('n', 'Y') # ('n', 'a') # ('n', 'g') # ('g', 'Y') # ('g', 'a') # ('g', 'n')

Как показано выше, использование функции itertools.permutations() аналогично itertools.combinations(). Разница только в их результатах.

6. itertools.accumulate(): создание накопленных элементов из итерируемого объекта.

Получение серии накопленных значений на основе итерируемого объекта является распространённым требованием. С помощью функции itertools.accumulate() нам не нужно писать никаких циклов для реализации.

import itertools import operator nums = [1, 2, 3, 4, 5] print(list(itertools.accumulate(nums, operator.mul))) # [1, 2, 6, 24, 120]

Вышеупомянутая программа будет такой, как показано ниже, если мы не хотим использовать operator.mul:

import itertools nums = [1, 2, 3, 4, 5] print(list(itertools.accumulate(nums, lambda a, b: a * b))) # [1, 2, 6, 24, 120]

7. itertools.repeat(), itertools.cycle(), itertools.count(): создание бесконечных итерируемых объектов

В некоторых случаях нам нужно получить бесконечную итерацию. Есть 3 полезные функции:

itertools.repeat(): многократна генерация одного и того же элемента

Например, мы можем получить три одинаковых «Yang» следующим образом:

import itertools print(list(itertools.repeat('Yang', 3))) # ['Yang', 'Yang', 'Yang']

itertools.cycle(): получение бесконечного итератора, зацикливание

Функция itertools.cycle не остановится, пока вы не разорвёте цикл:

import itertools count = 0 for c in itertools.cycle('Yang'): if count >= 12: break else: print(c, end=',') count += 1 # Y,a,n,g,Y,a,n,g,Y,a,n,g,

itertools.count(): генерация бесконечной последовательности чисел

Если всё, что нам нужно, это числа, используйте функцию itertools.count:

import itertools for i in itertools.count(0, 2): if i == 20: break else: print(i, end=" ") # 0 2 4 6 8 10 12 14 16 18

Как показано выше, её первый параметр — это начальный номер, а второй параметр — шаг.

8. itertools.pairwise(): лёгкое получение кортежа пар

Начиная с Python 3.10, модуль itertools имеет новую функцию с именем pairwise. Это небольшой и аккуратный инструмент для создания последовательных перекрывающихся пар из итерируемого объекта.

import itertools letters = ['a', 'b', 'c', 'd', 'e'] result = itertools.pairwise(letters) print(list(result)) # [('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', 'e')]

9. itertools.takewhile(): фильтрация элементов по-другому

itertools.takewhile() возвращает итератор, который генерирует элементы из итерируемого объекта, пока данная функция предиката оценивается как True.

import itertools nums = [1, 61, 7, 9, 2077] print(list(itertools.takewhile(lambda x: x < 100, nums))) # [1, 61, 7, 9]

Эта функция отличается от встроенной функции filter().

Функция filter будет проходить по всему списку:

nums = [1, 61, 7, 9, 2077] print(list(filter(lambda x: x < 10, nums))) # [1, 7, 9]

Однако функция itertools.takewhile, как следует из её названия, остановится, когда вычисляющая функция будет равна False:

import itertools nums = [1, 61, 7, 9, 2077] print(list(itertools.takewhile(lambda x: x < 10, nums))) # [1]

10. itertools.dropwhile(): обратная операция itertools.takewhile()

Эта функция кажется обратной идеей предыдущей.

Функция itertools.takewhile() возвращает элементы итерируемого объекта до тех пор, пока функция предиката имеет значение True, тогда как itertools.dropwhile() отбрасывает элементы итерируемого объекта до тех пор, пока функция предиката имеет значение True, а затем возвращает оставшиеся элементы.

import itertools nums = [1, 61, 7, 9, 2077] print(list(itertools.dropwhile(lambda x: x < 100, nums))) # [2077]

Спасибо за то, что дочитали эту статью до конца!

22
Начать дискуссию