[Перевод] Питонистический подход к циклам for: range() и enumerate()

Автор заметки, перевод которой мы сегодня публикуем, хочет рассказать о некоторых особенностях использования циклов for в Python.

uc9y89mf5p6ua8e5tq9kg7wr8qg.jpeg

Цикл 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())?

1ba550d25e8846ce8805de564da6aa63.png

© Habrahabr.ru