Цикл for — одна из базовых управляющих конструкций в любом языке программирования. Простейший цикл в языке Си выглядит так:
int i; for (i=0;i<N;i++) { // действия }
В Си нет более элегантного способа написать цикл for. В более сложных сценариях мы обычно прибегаем к вложенным циклам и множеству вспомогательных переменных (например, i
в примере выше).
К счастью, в Python все намного удобнее. У этого языка есть возможности, позволяющие писать лаконичные циклы — это очень упрощает нашу жизнь. В Python можно избежать вложенных циклов, а вспомогательные переменные объявлять вовсе не обязательно. А еще мы сами можем настроить цикл for
!
В этой статье мы расскажем вам о тонкостях написания цикла for
. Надеемся, вы прочувствуете всю красоту Python.
Обыденный сценарий: мы работаем со списком и нам нужно вывести и индексы, и соответствующие значения. Когда я только начал изучать Python, мой код выглядел примерно так:
for i in range(len(my_list)): print(i, my_list[i])
Да, это работает. Но это недостаточно «питонично». Через несколько месяцев изучения Python я решал эту задачу так:
for i, v in enumerate(my_list): print(i, v)
Как видите, встроенная функция enumerate значительно упрощает нашу жизнь.
Вложенные циклы — настоящая головная боль. Они усложняют не только сам код, но и его читаемость. Выход из этих циклов — задача тоже сложная. Чтобы найти ошибку, приходится приложить много усилий, ведь нужно проверить каждый внутренний цикл.
К счастью, существует очень полезная встроенная функция — product
. Она является частью встроенного модуля Python — itertools
. С ее помощью мы можем избавиться от вложенных циклов.
Рассмотрим пример:
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
Объявлено три списка чисел. Нам нужно вывести три числа (по одному из каждого списка), сумма которых равна 2077. Чтобы решить эту задачу, нам понадобилось три вложенных цикла. Код выглядит совсем не изящно.
А теперь опробуем функцию 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
Как видите, с помощью функции product количество циклов сокращается до одного.
Функция product
возвращает декартово произведение входных итераторов. Благодаря этому мы можем избежать написания вложенных циклов во многих сценариях.
Функция product
— лишь вершина айсберга. Изучение модуля itertools
сравнимо с открытием нового мира. В нем содержится множество полезных методов, которые могут упростить любой цикл. Полный список вы можете найти в официальной документации.
Рассмотрим несколько примеров.
В модуле itertools
есть как минимум три метода для создания бесконечных циклов:
1. Функция count
.
natural_num = itertools.count(1) for n in natural_num: print(n) # 1,2,3,...
2. Функция cycle
.
import itertools many_yang = itertools.cycle('Hello') for y in many_yang: print(y) # 'H','e','l','l','o','H','e','l',...
3. Функция repeat
.
many_yang = itertools.repeat('Hello') for y in many_yang: print(y) # 'Hello','Hello',...
Функция chain()
помогает нам объединять несколько итераторов в один.
from itertools import chain list_a = [1, 22] list_b = [7, 20] list_c = [3, 70] for i in chain(list_a, list_b, list_c): print(i) # 1,22,7,20,3,70
Функция groupby()
позволяет получить повторяющиеся элементы в итераторе и сгруппировать их.
from itertools import groupby for key, group in groupby('Pyttthhhonissst'): print(key, list(group)) # P ['P'] # y ['y'] # t ['t', 't', 't'] # h ['h', 'h', 'h'] # o ['o'] # n ['n'] # i ['i'] # s ['s', 's', 's'] # t ['t']
Как видите, дублирующиеся буквы сгруппированы. Более того, мы можем расширить функционал groupby()
. Например, указать, что нужно игнорировать регистр:
from itertools import groupby for key, group in groupby('PyYyYTTthHOoOnisst', lambda x: x.upper()): print(key, list(group)) # P ['P'] # Y ['y', 'Y', 'y', 'Y'] # T ['T', 'T', 't'] # H ['h', 'H'] # O ['O', 'o', 'O'] # N ['n'] # I ['i'] # S ['s', 's'] # T ['t']
После ознакомления с примерами пора наконец разобраться, почему же циклы в Python такие гибкие и изящные. Этими своими свойствами они обязаны тому, что к итератору в цикле for
можно применять функции. Во всех примерах, приведенных выше, к итераторам применялась какая-нибудь функция. Шаблон в целом выглядит так:
for x in function(iterator)
То есть, суть itertools
проста — этот модуль применяет часто используемые функции к итератору. Если вы забыли какую-либо функцию из itertools
— реализуйте ее самостоятельно. Также стоит заметить, что все эти функции — генераторы. Вот почему с их помощью мы можем создавать бесконечные циклы.
Таким образом, написав генератор, вы можете настроить цикл for
так, как вам необходимо.
Рассмотрим простой пример:
def even_only(num): for i in num: if i % 2 == 0: yield i my_list = [1, 9, 3, 4, 2, 5] for n in even_only(my_list): print(n) # 4 # 2
Как видите, мы объявляем генератор — even_only
. Если мы встроим этот генератор в цикл, то итерация будет происходить только по четным элементам списка.
Пример выше — лишь для объяснения принципа работы. Существует множество других способов решения этой задачи — например, генераторы списков.
my_list = [1, 9, 3, 4, 2, 5] for n in (i for i in my_list if not i % 2): print(n) # 4 # 2
Циклы в Python могут быть изящны и гибки. Такими их делают встроенные функции и генераторы.
Pydantic - это мощная библиотека проверки данных и управления настройками для Python, созданная для повышения…
Python предлагает набор библиотек, удовлетворяющих различные потребности в визуализации, будь то академические исследования, бизнес-аналитика или…
В Python для представления данных в двоичной форме можно использовать байты. Из этой статьи вы…
В этой статье рассказывается о том, что такое Werkzeug и как Flask использует его для…
При работе с датами часто возникает необходимость прибавлять к дате или вычитать из нее различные…
В этом руководстве мы рассмотрим, как добавить социальную аутентификацию с помощью GitHub и Google в…