Что делать, если индексы при обработке последовательностей нам все-таки нужны?
Одним из существенных и весьма приятных отличий Python от других языков программирования является то, что он при обработке различных последовательностей в for циклах позволяет получать доступ к элементам таких последовательностей не через соответствующие индексы, а напрямую. Это значительно упрощает код, делает его более компактным и читабельным. Однако бывают случае, когда по логике программы наряду с элементами обрабатываемых последовательностей приходится все-таки иметь дело и с индексами этих последовательностей. Наиболее очевидным в этом случае является игнор всяких там рекомендаций по стилю Python кода типа PEP 8 и использование индексов по аналогии кодинга в старом добром С:
>>> fruit_basket = ["вишня", "груша", "арбуз", "яблоко", "черника"]
>>> for i in range(len(fruit_basket)):
... print(i+1, fruit_basket[i])
...
1 вишня
2 груша
3 арбуз
4 яблоко
5 черника
Но, этот код в придачу к нарушению стиля является еще и ужасно громоздким с кучей излишних функций и переменных. Поэтому, если кроме доступа к элементам последовательности, вам действительно параллельно еще нужен какой-то их подсчет, то наиболее оправданным будет использования Python функции enumerate().
Функция enumerate() применительно к итерируемым последовательностям (структурам данных, элементы которых доступны через индекс) позволяет создать объект, генерирующий двухэлементные кортежи, состоящие соответственно из индекса и из значения итерируемого элемента.
Давайте опробуем эту функцию на примере кода из нашего предыдущего примера:
>>> fruit_basket = ["вишня", "груша", "арбуз", "яблоко", "черника"]
>>> for fruit in enumerate(fruit_basket):
... print(fruit)
...
(0, 'вишня')
(1, 'груша')
(2, 'арбуз')
(3, 'яблоко')
(4, 'черника')
В итоге при итерации списка fruit_basket, переданного в качестве 1-го аргумента функции enumerate(), мы получили 5-ть отдельных кортежей (соответственно числу элементов в этом списке), каждый из которых содержит, как индекс соответствующего элемента, так и его значение.
Если же нам нужно изменить индекс, начиная с которого должны будут выводиться элементы нашего списка, то это можно сделать с помощью 2-го аргумента функции enumerate(), посредством ключевого слова start
:
>>> fruit_basket = ["вишня", "груша", "арбуз", "яблоко", "черника"]
>>> for fruit in enumerate(fruit_basket, start=1):
... print(fruit)
...
(1, 'вишня')
(2, 'груша')
(3, 'арбуз')
(4, 'яблоко')
(5, 'черника')
Фактически, с учетом наличия 2-го аргумента в функции enumerate(), первые элементы в каждом из итерируемых кортежей (переменной fruit
внутри цикла) можно воспринимать не буквально, как индексы элементов, а просто, как порядковые номера или числа, ассоциирующиеся со значениями нашего списка.
Следовательно, при такой ситуации нам вполне может понадобится распаковывать получаемые кортежи с тем, чтобы в программу можно было получать два отдельных значения (две переменных), а именно порядковый номер элемента списка и непосредственное значение этого элемента. Для этого попробуем представить переменную fruit
в виде fruit[0]
и fruit[1]
:
>>> fruit_basket = ["вишня", "груша", "арбуз", "яблоко", "черника"]
>>> for fruit in enumerate(fruit_basket, start=1):
... print(fruit[0], fruit[1])
...
1 вишня
2 груша
3 арбуз
4 яблоко
5 черника
Но лучше и нагляднее при распаковке кортежей все же использовать поименованные переменные следующим образом:
>>> fruit_basket = ["вишня", "груша", "арбуз", "яблоко", "черника"]
>>> for fruit in enumerate(fruit_basket, start=1):
... n, berry = fruit
... print(n, berry, fruit)
...
1 вишня (1, 'вишня')
2 груша (2, 'груша')
3 арбуз (3, 'арбуз')
4 яблоко (4, 'яблоко')
5 черника (5, 'черника')
Примечание: Следует отметить, что при распаковке кортежей в поименованные переменные очень важно, чтобы число присваиваемых переменных (тех, что слева) строго совпадало с числом элементов, имеющихся в кортеже. В данном случае, у нас кортеж имеет два элемента. Следовательно, этому кортежу мы сопоставляем две переменные:
n
иberry
.
Еще одной приятной особенностью Python является то, что распаковка кортежей в коде тут разрешена везде, где может происходить присваивание. Например, в строке с определением for цикла переменная слева от оператора принадлежности in также является присваиваемой. Поэтому, наши кортежи мы можем распаковывать одновременно с циклом:
>>> fruit_basket = ["вишня", "груша", "арбуз", "яблоко", "черника"]
>>> for n, berry in enumerate(fruit_basket, start=1):
... print(n, berry)
...
1 вишня
2 груша
3 арбуз
4 яблоко
5 черника
В этом примере проиллюстрирован наиболее распространенный вариант применения функции enumerate() с одновременной распаковкой выводимых ею кортежей в поименованные переменные прямо в строке с определением цикла for.
Подытоживая все сказанное выше, при планировании обработки последовательностей посредством for цикла в Python, наверное, прежде стоит спросить себя: нужен ли мне вообще какой-то счетчик в этом цикле?- Если надобности в таком счетчики у вас нет, то просто постарайтесь использовать for цикл в максимально простой форме записи, без каких-либо излишеств. Если же у вас все-таки есть потребность в порядковых номерах или каких-либо других числах, ассоциируемых с обрабатываемыми вами последовательностями, то наилучшим способом удовлетворения таковой потребности будет использования встроенной в Python функции enumerate().
Возможно будет интересно
🏆 Hello, world!
Мы вчера запустили новый www.pylot.me. Должны были в следующую среду, но запустили вчера.
Как практиковаться в Python?
Для улучшения качества знаний и повышения уровня программиста, необходим постоянный практикум. Где можно это организовать самостоятельно, и как практиковаться в Python?
Условные конструкции и сопоставление структурных шаблонов
Шпаргалка по условным конструкциям и сопоставлению структурных шаблонов