Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Цикл for Python: Списки

Ранее мы рассматривали цикл while. Эта конструкция предназначена для повторения некоего набора действий — все, что выходит за рамки повторения, требует дополнительных средств для хранения состояния.

Возьмем для примера счетчик, который мы изменяем в цикле. При работе с коллекциями нам нужно как-то выбирать, с каким элементом мы работаем в текущей итерации. Так что же, использовать переменную-счетчик каждый раз?

Любой программист всегда стремится автоматизировать рутинную работу, и авторы языков — не исключение. Поэтому в Python для работы с коллекциями существует другой вид цикла — цикл for.

Стоит сразу отметить, что этот цикл не похож на циклы с тем же названием в других языках программирования. Во многих языках этот цикл всего лишь дополняет условие завершения цикла переменной-счетчиком.

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

Синтаксис

Цикл for устроен очень просто:

for element in collection:
    print(element)  # this is body of cycle

Заметьте, в простейшем случае у цикла даже нет явного условия завершения. Цикл просто останавливается, когда в коллекции заканчиваются элементы.

Пример выше сработает для кортежей и списков — в этом случае будут выведены все элементы. А еще можно проитерировать — так называют обход коллекции. В таком случае переменная цикла (element) будет поочередно содержать все символы строки:

for c in 'Hello!':
    print(c)

# => H
# => e
# => l
# => l
# => o
# => !

Но что же делать, если нам нужно не просто получить элементы списка один за другим, но и изменить эти элементы? Ведь для этого нам понадобится индекс каждого элемента.

На этот случай в Python есть удобная функция «пронумеровать» — enumerate. Эта функция снабжает каждый элемент индексом, складывая каждый индекс вместе с элементом в кортеж. Кортежи эти, как правило, прямо в первой строке цикла и распаковывают:

items = ['foo', 'bar', 'baz']
for (index, elem) in enumerate(items):
    items[index] = elem + '!'

print(items)  # => ['foo!', 'bar!', 'baz!']

В этом цикле мы заменили каждый элемент оригинальным значением, дополненным строкой '!'. Этот код можно было написать и несколько иначе:

items = ['foo', 'bar', 'baz']
for (index, _) in enumerate(items):
    items[index] += '!'

print(items)  # => ['foo!', 'bar!', 'baz!']

В этот раз мы вообще не используем сами элементы — только их индексы. Поэтому вместо переменной цикла, в которую распаковываются элементы, у нас стоит прочерк.

Это не какая-то особая переменная, а всего лишь соглашение: в Python часто незначимые в этом контексте вещи записывают в переменную _.

Заметьте: в последнем примере речь и шла об индексах, но мы все равно не использовали длину коллекции. Функция enumerate тоже знает, где остановиться — в конце исходной коллекции.

Управление циклом с помощью break и continue

Иногда не нужно доходить до конца коллекции. Например, при поиске элемента, удовлетворяющего некоему условию. Как только мы нашли первый подходящий элемент, нам неплохо бы сэкономить ресурсы и завершить цикл.

Такой ранний выход из цикла делается с помощью команды break. Вот цикл поиска первого положительного числа:

items = [-2, 0, -10, 3, 5, -1]
for item in items:
    if item > 0:
        break

print(item)  # => 3

Как вы могли заметить, переменная цикла оказалась доступна и после его завершения. Однако если коллекция окажется пустой, то переменная не будет определена — имейте это в виду.

Этот код, кажется, работает как надо. Однако если в списке не встретится ни одного положительного числа, то в переменной item окажется просто последний элемент списка.

Как же понять, что мы ничего не нашли? На помощь приходит else. В цикле else выполняется, если цикл так и не прервался с помощью break. Для алгоритмов поиска — это идеальный вариант. Перепишем наш пример с применением else:

items = [-2, 0, -10, -1]
for item in items:
    if item > 0:
        break
else:
    item = None

print(item)  # => None

Теперь представим ситуацию, что мы в процессе выполнения тела цикла поняли, что остаток тела выполнять незачем и можно сразу перейти к следующей итерации.

Для перехода к следующей итерации предназначена команда continue. Ее использование продемонстрирует следующий пример: мы читаем строки, содержащие строчки кода, но нам не нужно обрабатывать код тех строчек, которые начинаются с символа #. Вот так будет выглядеть код:

lines_of_code = [
    '# begin of example',
    'echo 123',
    'cd foo',
    '# end']
for line in lines_of_code:
    if line[:1] == '#':
        continue
    # here we process a code
    print(line)

# => echo 123
# => cd foo

Конечно, мы могли бы обойтись условной конструкцией. Однако в этом случае код, обрабатывающий нужные строки, был бы вложен глубже. А нам нужно стремиться держать вложенность кода в разумных пределах, иначе код очень быстро станет очень сложным для прочтения.

break, continue, else и цикл while

Ветка else и команды break и continue доступны и для цикла while. Вот комплексный пример, демонстрирующий все эти возможности:

tries_count = 3
while tries_count:
    print('>>> ', end='')
    command = input()
    if not command:
        continue
    if command in ('echo', 'cd', 'help'):
        break
    print('Unknown command!')
    tries_count -= 1
else:
    print('Too many bad tries!')
    command = None

Этот код просит пользователя ввести одну из команд, игнорирует пустой ввод, ограничивает кол-во попыток ввода. Подумайте, какая часть тела цикла за что отвечает.

Цикл for и изменяемые коллекции

Хотим предостеречь от изменения состава списка во время обхода его же в цикле for. Если вы будете удалять элементы из списка, по которому проходитесь — или даже всего лишь добавлять новые элементы в конец.

Результат может быть неожиданным, вплоть до завершения программы с ошибкой. Лучше наполнять новый список в процессе обхода старого.

Если вы хотите обязательно изменить состав исходного списка, то обходите в цикле копию списка:

for x in original_list[:]:
    original_list.pop(0)

Еще можно создать временный список, а потом очистить исходный и добавить элементы из временного:

new_list = []
for x in original_list:
    ...
original_list[:] = []  # удаляем старое содержимое
original_list.extend(new_list)

Естественно можно скомбинировать эти два варианта и сначала сделать копию, потом очистить оригинал, и затем уже в цикле обхода копии добавлять новые элементы.


Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты.

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы

С нуля до разработчика. Возвращаем деньги, если не удалось найти работу.

Иконка программы Python-разработчик
Профессия
с нуля
Разработка веб-приложений на Django
2 февраля 10 месяцев

Используйте Хекслет по-максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»