[Перевод] Питонистический подход к циклам for: range() и enumerate()
Автор заметки, перевод которой мы сегодня публикуем, хочет рассказать о некоторых особенностях использования циклов for
в Python.
Цикл for
— это один из краеугольных камней программирования. С этими циклами будущие программисты знакомятся в самом начале учёбы и, после первого знакомства, пользуются ими постоянно.
Если вы занялись разработкой на Python, имея опыт работы с другим популярным языком программирования, вроде PHP или JavaScript, то вам знакома методика применения переменной-счётчика, хранящей, например, индекс текущего элемента массива, обрабатываемого в цикле. Вот пример работы с циклом, написанный на JavaScript:
let scores = [54,67,48,99,27];
for(const i=0; i < scores.length; i++) {
console.log(i, scores[i]);
}
/*
0 54
1 67
2 48
3 99
4 27
*/
Работая с циклами for
очень важно понимать то, что эти циклы не перебирают массивы. Они лишь дают программисту механизм для работы с переменной-счётчиком, которая используется для обращения к элементам обрабатываемых массивов.
В предыдущем примере переменная i
не имеет какого-то явного отношения к массиву scores
. Она всего лишь хранит некое число, которое увеличивается на 1 в каждой итерации цикла, и которое, как оказывается, подходит для последовательного обращения к элементам массива по их индексам.
Старый (неудачный) способ работы с массивами
В Python нет традиционных циклов for
, подобных тому, что показан выше. Правда, если вы похожи на меня, то первым вашим желанием при освоении Python станет поиск способа создания цикла, с которым вам привычно и удобно работать.
В результате вы можете обнаружить функцию range()
и написать на Python нечто подобное следующему:
scores = [54,67,48,99,27]
for i in range(len(scores)):
print(i, scores[i])
"""
0 54
1 67
2 48
3 99
4 27
"""
Проблема этого цикла заключается в том, что он не очень хорошо соответствует идеологии Python. В нём мы не перебираем список, а, вместо этого, используем вспомогательную переменную i
для обращения к элементам списка.
На самом деле, даже в JavaScript существуют методы, позволяющие перебирать массивы, так сказать, без посредников. Речь идёт о циклах forEach
и for of
.
Использование функции enumerate ()
Если вам нужно адекватным образом отслеживать «индекс элемента» в for
-цикле Python, то для этого может подойти функция enumerate()
, которая позволяет «пересчитать» итерируемый объект. Её можно использовать не только для обработки списков, но и для работы с другими типами данных — со строками, кортежами, словарями.
Эта функция принимает два аргумента: итерируемый объект и необязательное начальное значение счётчика.
Если начальное значение счётчика enumerate()
не передаётся — оно, по умолчанию, устанавливается в 0
. Функция создаёт объект, генерирующий кортежи, состоящие из индекса элемента и самого этого элемента.
scores = [54,67,48,99,27]
for i, score in enumerate(scores):
print(i, score)
Такой код получился гораздо чище кода из предыдущего примера. Мы ушли от работы со списком индексов, мы перебираем сами значения, получая к ним прямой доступ в цикле for,
и видим значения, с которыми работаем, в объявлении цикла.
Вот одна приятная возможность, которая понравится тем, кому нужно выводить нумерованные списки так, чтобы номер первого элемента был бы не 0
, в соответствии с его индексом, а 1
. Обычно для того, чтобы это сделать, приходится менять выводимый номер элемента. Например — так: i + 1
. При использовании же функции enumerate()
достаточно передать ей, в качестве второго аргумента, то число, с которого нужно начинать нумерацию. В нашем случае — 1
:
scores = [54,67,48,99,27]
for i, score in enumerate(scores, 1):
print(i, score)
"""
1 54
2 67
3 48
4 99
5 27
"""
Итоги
Надеюсь, этот небольшой рассказ о циклах for
в Python позволил вам узнать что-то новое об этом языке.
Уважаемые читатели! Знаете ли вы ещё какие-нибудь способы применения функции enumerate()
? Кажутся ли вам циклы, построенные с использованием enumerate()
, более читабельными, чем циклы, созданные с использованием range(len())
?