2.12. Цикли

Цикл виконує один і той самий блок коду повторно. Python має дві форми: while – продовжує виконання, поки умова залишається істинною, та for – перебирає елементи послідовності.

Side-by-side flowcharts. while: test the condition, run the body if true, repeat. for: take the next item from the iterable, run the body, repeat until exhausted.

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. Вбудоване присвоєння з :=

Оператор walrus := – це присвоєння, яке водночас є виразом. Він прив’язує ім’я та обчислюється до того самого значення одночасно. У циклі 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)

Обидві форми роблять одне й те саме. Використовуйте :=, коли дублювання присвоєння дійсно знижує читабельність; не вдавайтесь до нього заради хитромудрості. Дужки обов’язкові в більшості позицій, щоб вираз залишався однозначним.