Программа, которая принимает решения и повторяет действия
if / elif / else в правильном порядкеand, or, not и цепочек сравненийfor по range и циклом whilebreak и пропускать шаг через continueif выполняет блок, только если условие истинно. Блок — строки с одинаковым отступом после двоеточия. elif («иначе если») проверяется, только когда все условия выше были ложны; else — когда не подошло ничего.
# Перевод баллов (0–100) в оценку
score = int(input("Баллы: "))
if score < 0 or score > 100:
print("Ошибка: баллы должны быть от 0 до 100")
elif score >= 85:
print("Оценка: 5 (отлично)")
elif score >= 70:
print("Оценка: 4 (хорошо)")
elif score >= 55:
print("Оценка: 3 (удовлетворительно)")
else:
print("Оценка: 2 (не зачтено)")
$ python3 grade.py
Баллы: 92
Оценка: 5 (отлично)
$ python3 grade.py
Баллы: 70
Оценка: 4 (хорошо)
$ python3 grade.py
Баллы: 54
Оценка: 2 (не зачтено)
$ python3 grade.py
Баллы: 120
Ошибка: баллы должны быть от 0 до 100
Python проверяет условия сверху вниз и выполняет первую подходящую ветку — остальные уже не смотрит. Поэтому 70 баллов дали «4»: условие score >= 85 ложно, score >= 70 истинно, до проверки на 55 дело не дошло. Отсюда правило: от узкого условия к широкому. Если порядок перепутать, программа работает, но неверно:
score = int(input("Баллы: "))
if score >= 55:
print("Оценка: 3")
elif score >= 70:
print("Оценка: 4")
elif score >= 85:
print("Оценка: 5")
$ python3 grade_bad.py
Баллы: 92
Оценка: 3
92 больше 55, первая же ветка сработала. Проверку некорректных данных (баллы вне 0–100) ставят первой — чтобы дальше работать только с правильными значениями.
and — истинно, если истинны обе части; or — если истинна хотя бы одна; not — отрицание. Сравнения можно сцеплять: 14 <= age < 18 означает «age от 14 включительно до 18».
>>> age = 17
>>> age >= 18
False
>>> 14 <= age < 18
True
>>> age >= 18 or age == 17
True
>>> not age >= 18
True
>>> x = 0
>>> x != 0 and 10 / x > 1
False
>>> 10 / x > 1 and x != 0
Traceback (most recent call last):
File "<python-input-7>", line 1, in <module>
10 / x > 1 and x != 0
~~~^~~
ZeroDivisionError: division by zero
>>> name = ""
>>> name or "гость"
'гость'
Обе логические операции ленивые: and не вычисляет правую часть, если левая ложна, or — если левая истинна. Поэтому x != 0 and 10 / x > 1 безопасно, а то же самое в обратном порядке падает с делением на ноль. Проверка, которая защищает от ошибки, ставится слева.
or возвращает не True, а первое истинное значение — отсюда приём «значение по умолчанию»: name or "гость".
Приоритет: not выше and, and выше or. Правило високосного года — «делится на 4 и не делится на 100, или делится на 400» — записывается дословно:
year = int(input("Год: "))
if year % 4 == 0 and year % 100 != 0 or year % 400 == 0:
print(year, "— високосный, в феврале 29 дней")
else:
print(year, "— обычный, в феврале 28 дней")
$ python3 leap.py
Год: 2028
2028 — високосный, в феврале 29 дней
$ python3 leap.py
Год: 1900
1900 — обычный, в феврале 28 дней
$ python3 leap.py
Год: 2000
2000 — високосный, в феврале 29 дней
Для читателя лучше поставить скобки, даже если они не нужны интерпретатору: (year % 4 == 0 and year % 100 != 0) or year % 400 == 0.
for перебирает элементы последовательности: на каждом шаге переменная цикла получает следующий элемент и выполняется тело. Самая частая последовательность — range:
| Запись | Числа |
|---|---|
range(5) | 0, 1, 2, 3, 4 — от нуля, не включая 5 |
range(1, 11) | 1 … 10 |
range(1, 11, 3) | 1, 4, 7, 10 — с шагом 3 |
range(10, 0, -3) | 10, 7, 4, 1 — обратный отсчёт |
>>> list(range(5))
[0, 1, 2, 3, 4]
>>> list(range(1, 11, 3))
[1, 4, 7, 10]
>>> list(range(10, 0, -3))
[10, 7, 4, 1]
>>> for i in range(3):
... print("Повтор", i)
...
Повтор 0
Повтор 1
Повтор 2
list(range(...)) здесь только для того, чтобы увидеть числа: сам range их не хранит, а выдаёт по одному. Поэтому range(1_000_000_000) не занимает память. Правая граница не включается — это сделано, чтобы range(n) давал ровно n шагов.
for перебирает не только числа: по строке — символы, по списку — элементы (модули 04 и 05).
Цикл внутри цикла: на каждый шаг внешнего внутренний проходит целиком. Таблица умножения — внешний цикл по строкам, внутренний по столбцам:
# Таблица умножения 1..5
for row in range(1, 6):
for col in range(1, 6):
print(f"{row * col:4}", end="")
print()
$ python3 table.py
1 2 3 4 5
2 4 6 8 10
3 6 9 12 15
4 8 12 16 20
5 10 15 20 25
end="" оставляет числа строки рядом, print() после внутреннего цикла переводит строку. Формат {…:4} — ширина 4, числа выравниваются по правому краю. Внутреннее тело выполнилось 5 × 5 = 25 раз: вложенные циклы быстро умножают работу, и на больших данных это заметно.
while повторяет тело, пока условие истинно. Его выбирают, когда заранее неизвестно число шагов: пока в числе есть цифры, пока пользователь не угадал, пока файл не кончился.
# Сумма цифр числа
n = int(input("Число: "))
total = 0
while n > 0:
total += n % 10
n //= 10
print("Сумма цифр:", total)
$ python3 digits.py
Число: 2026
Сумма цифр: 10
$ python3 digits.py
Число: 987654321
Сумма цифр: 45
n % 10 — последняя цифра, n //= 10 — отбросить её. Когда цифр не осталось, n становится 0 и цикл заканчивается.
while не меняет то, от чего зависит условие, цикл не закончится никогда. Остановить такую программу — Ctrl+C. Перед запуском спросите себя: что в теле приближает выход?count = 10
while count > 0:
print(count)
count + 1 # ошибка: значение вычислено и выброшено, count не меняется
Нужно count -= 1. Ошибка двойная: и операция не та, и результат не присвоен.
break немедленно завершает цикл. continue завершает текущий шаг и переходит к следующему. Типичный приём — while True с выходом через break: условие окончания проверяется в середине тела, когда нужные данные уже получены.
import random
secret = random.randint(1, 100)
tries = 0
print("Я загадал число от 1 до 100.")
while True:
guess = int(input("Ваш вариант: "))
tries += 1
if guess < secret:
print("Больше")
elif guess > secret:
print("Меньше")
else:
print(f"Угадали за {tries} попыток")
break
$ python3 guess.py
Я загадал число от 1 до 100.
Ваш вариант: 50
Меньше
Ваш вариант: 25
Меньше
Ваш вариант: 12
Больше
Ваш вариант: 18
Меньше
Ваш вариант: 15
Больше
Ваш вариант: 16
Угадали за 6 попыток
Модуль random подключается строкой import random (подробно — в модуле 06); random.randint(1, 100) — случайное целое от 1 до 100 включительно. Деление отрезка пополам гарантирует, что любое число от 1 до 100 угадывается не больше чем за 7 попыток.
continue удобен, чтобы отсеять неподходящее, не заворачивая всё остальное тело в if:
# Среднее положительных чисел; пустая строка — конец ввода
total = 0
count = 0
while True:
line = input("Число (Enter — закончить): ")
if line == "":
break
number = float(line)
if number <= 0:
print(" пропускаю: нужно положительное")
continue
total += number
count += 1
if count > 0:
print(f"Чисел: {count}, среднее: {total / count:.2f}")
else:
print("Чисел не было")
$ python3 average.py
Число (Enter — закончить): 4
Число (Enter — закончить): -2
пропускаю: нужно положительное
Число (Enter — закончить): 5.5
Число (Enter — закончить): 0
пропускаю: нужно положительное
Число (Enter — закончить): 10
Число (Enter — закончить):
Чисел: 3, среднее: 6.50
$ python3 average.py
Число (Enter — закончить):
Чисел не было
Проверка count > 0 после цикла — не формальность: без неё пустой ввод закончился бы делением на ноль.
У for и while может быть ветка else: она выполняется, если цикл завершился сам, без break. Это естественная запись поиска: «перебрал всё и не нашёл».
n = int(input("Число: "))
for d in range(2, n):
if n % d == 0:
print(n, "— составное, делится на", d)
break
else:
print(n, "— простое")
$ python3 prime.py
Число: 91
91 — составное, делится на 7
$ python3 prime.py
Число: 97
97 — простое
Без else понадобилась бы переменная-флаг found = False, которую цикл переключает. Конструкция редкая и путает тех, кто её не знает, — используйте, но не злоупотребляйте.
Когда одно значение сравнивается со многими вариантами, вместо длинной цепочки elif можно написать match (Python 3.10 и новее). | — «или», _ — всё остальное.
>>> command = "stop"
>>> match command:
... case "start" | "run":
... print("Запускаю")
... case "stop":
... print("Останавливаю")
... case _:
... print("Неизвестная команда")
...
Останавливаю
Это та же цепочка if command == "start" or command == "run": … elif …, записанная короче. У match есть и более мощные возможности — разбор структуры данных по образцу, — но для начала достаточно выбора по значению.
if / elif / else проверяются сверху вниз до первой подходящей ветки: от узкого условия к широкомуand и or ленивые: защитную проверку ставьте слеваrange(a, b) не включает b; range(n) — ровно n шагов от нуляfor — когда известно, что перебирать; while — когда известно условие остановкиwhile должно меняться то, от чего зависит условиеbreak — выйти из цикла, continue — к следующему шагу, else у цикла — «прошёл без break»