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]

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

+1
4
+1
4
+1
0
+1
0
+1
0

Ответить

Ваш адрес email не будет опубликован. Обязательные поля помечены *