- Синтаксис
- Управление циклом с помощью break и continue
- break, continue, else и цикл while
- Цикл for и изменяемые коллекции
Ранее мы рассматривали цикл 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):
print(f'{index} {elem}')
# => 0 foo
# => 1 bar
# => 2 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
# Здесь происходит обработка кода
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)
Естественно можно скомбинировать эти два варианта и сначала сделать копию, потом очистить оригинал, и затем уже в цикле обхода копии добавлять новые элементы.
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
- Статья «Как учиться и справляться с негативными мыслями»
- Статья «Ловушки обучения»
- Статья «Сложные простые задачи по программированию»
- Вебинар «Как самостоятельно учиться»
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.