2.12. Циклы

Цикл многократно выполняет один и тот же блок кода. В Python есть две формы: while, который продолжается, пока условие остаётся истинным, и for, который обходит элементы последовательности.

Блок-схемы рядом друг с другом. while: проверить условие, выполнить тело, если истинно, повторить. for: взять следующий элемент из итерируемого объекта, выполнить тело, повторять, пока он не исчерпан.

while продолжает проверять условие; for обходит последовательность, пока она не исчерпана.

2.12.1. Циклы while

Цикл while проверяет своё условие перед каждой итерацией и выполняет тело, пока проверка не станет ложной:

count = 0
while count < 5:
    print(count)
    count += 1

Вывод:

0
1
2
3
4

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

while True:
    step()
    if done():
        break

2.12.2. Циклы for

Цикл for обходит элементы итерируемого объекта – списка, кортежа, строки, байтов, словаря или любого другого объекта, поддерживающего итерацию:

for fruit in ["apple", "banana", "cherry"]:
    print(fruit)

Вывод:

apple
banana
cherry

Та же форма работает со строкой, где каждый элемент – это строка из одного символа:

for letter in "OpenMV":
    print(letter)

Вывод:

O
p
e
n
M
V

Итерация словаря напрямую возвращает его ключи в порядке вставки:

for key in {"a": 1, "b": 2}:
    print(key)

Вывод:

a
b

При каждом проходе переменная цикла (fruit, letter, key) связывается со следующим элементом. После завершения цикла переменная сохраняет значение из последней итерации.

2.12.3. range

Для циклов по числовому диапазону используйте range():

  • range(stop) – 0, 1, …, stop - 1.

  • range(start, stop) – start, start + 1, …, stop - 1.

  • range(start, stop, step) – с заданным шагом (отрицательные значения отсчитывают вниз).

for i in range(5):           # 0, 1, 2, 3, 4
    print(i)

for i in range(2, 8, 2):     # 2, 4, 6
    print(i)

for i in range(10, 0, -1):   # 10, 9, ..., 1
    print(i)

range() генерирует значения лениво – он не строит список в памяти. Чтобы получить настоящий list, оберните его: list(range(10)).

2.12.4. enumerate

Когда циклу нужны и индекс, и элемент, enumerate() выдаёт пары (index, item):

for i, name in enumerate(["a", "b", "c"]):
    print(i, name)
# 0 a
# 1 b
# 2 c

Начните индекс не с нуля, передав второй аргумент: enumerate(items, start=1).

2.12.5. zip

Чтобы обходить два (или более) итерируемых объекта синхронно, используйте zip(). Он выдаёт по одному кортежу на каждую позицию и останавливается на самом коротком из входных данных:

names  = ["alice", "bob", "carol"]
scores = [88, 92, 70]

for name, score in zip(names, scores):
    print(name, score)

Вывод:

alice 88
bob 92
carol 70

2.12.6. Встроенное присваивание с :=

Оператор моржа := – это присваивание, которое одновременно является выражением. Он связывает имя и вычисляется в то же значение в один и тот же момент. В цикле while это сворачивает распространённый шаблон «прочитать, проверить, тело» в одну строку:

# without walrus
value = next_value()
while value is not None:
    process(value)
    value = next_value()

# with walrus
while (value := next_value()) is not None:
    process(value)

Обе формы делают одно и то же. Используйте :=, когда дублирование присваивания действительно вредит читаемости; не используйте его просто ради хитрости. Скобки обязательны в большинстве позиций, чтобы выражение оставалось однозначным.