💻 Рабочие примеры

⚡ Кратко: шпаргалка по урокам 08–10

age = 15
category = "Ребёнок" if age <= 12 else "Подросток" if age <= 17 else "Взрослый"

import math
print(math.sqrt(16), round(0.1 + 0.2, 2))  # 4.0 0.3

from decimal import Decimal
print(Decimal("0.1") + Decimal("0.2"))     # 0.3
ТемаИнструментПример
Ветвлениеif/elif/elseif x > 0: ... elif x == 0: ... else: ...
Комбинация условийand, or, not, цепочное сравнение0 <= x <= 10
Короткий выбортернарный оператор, match-casea if cond else b
Математикавстроенные функции, модуль mathmath.sqrt(16) → 4.0
Точные деньгиdecimal.DecimalDecimal('0.1') + Decimal('0.2') → 0.3
Топ-3 ошибки: забыть int()/float() для input() · сравнивать float через == вместо math.isclose() · путать and и or в условиях.

Двенадцать примеров закрывают весь блок уроков 08 — операторы ветвления, 09 — практикум 2 и 10 — математические функции, хранение чисел, модули: от простого if-elif-else до точных денежных расчётов через Decimal. Порядок — от простого к сложному, весь вывод в комментариях получен реальным запуском кода.

Пример 1. Возрастная категория: цепочка if-elif-else

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

📄 examples/age_category.py
age = 15

if age <= 2:
    category = "Младенец"
elif age <= 12:
    category = "Ребёнок"
elif age <= 17:
    category = "Подросток"
else:
    category = "Взрослый"

print(f"Категория: {category}.")
# Категория: Подросток.

Что происходит: условия проверяются сверху вниз, выполняется первая истинная ветка. Порядок условий важен: достаточно проверить верхнюю границу каждой категории, потому что более младшие значения уже отсеяны предыдущими elif.

Пример 2. Неявное преобразование в bool (truthy/falsy)

В условии if Python сам решает, что считать «правдой». Это экономит код, но нужно точно знать список «ложных» значений.

📄 examples/truthiness.py
name = "Alice"
if name:
    print(f"Привет, {name}!")

value = 0
if value:
    print("Ноль не выведется")
else:
    print("value ложно, ветка else")

items = []
if items:
    print("Список непуст")
else:
    print("Пустой список — falsy")

print(bool(""), bool("0"), bool(0), bool(0.0), bool(None), bool([]), bool({}))
# Привет, Alice!
# value ложно, ветка else
# Пустой список — falsy
# False True False False False False False

Что происходит: False дают только 0, 0.0, пустая строка "", None и пустые коллекции ([], {}). Обратите внимание на bool("0") — строка с одним нулём непустая, поэтому она True.

Пример 3. Независимые if против цепочки if-elif-else

Несколько отдельных if проверяются независимо и могут сработать все сразу; в цепочке if-elif-else выполняется только одна ветка.

📄 examples/independent_vs_elif.py
x = 8

print("Независимые if:")
if x > 5:
    print("x больше 5")
if x < 10:
    print("x меньше 10")
if x % 2 == 0:
    print("x чётное")

print("Цепочка if-elif-else:")
if x > 5:
    print("x больше 5 (elif-ветка)")
elif x < 10:
    print("x меньше 10 (elif-ветка) — не выполнится, т.к. первая ветка уже сработала")
else:
    print("x меньше или равно 5")
# Независимые if:
# x больше 5
# x меньше 10
# x чётное
# Цепочка if-elif-else:
# x больше 5 (elif-ветка)

Что происходит: все три независимых if вывели строку, потому что каждое условие проверялось само по себе. В цепочке напечаталась только первая истинная ветка — вторая проверка x < 10 вообще не выполнялась, хотя тоже истинна.

Пример 4. Вложенные условия → плоская структура (guard clauses)

Вложенные if работают, но растут вширь с каждым уровнем. Guard clauses, and/or/not и цепочные сравнения делают ту же логику плоской и читаемой.

📄 examples/nested_vs_flat.py
role = "admin"
access = False

# Вложенный вариант
if role == "admin":
    if access:
        print("Вложенный: доступ разрешён")
    else:
        print("Вложенный: доступ запрещён")
else:
    print("Вложенный: недостаточно прав")

# Плоский вариант через guard clauses и логические операторы
if role != "admin":
    print("Плоский: недостаточно прав")
elif not access:
    print("Плоский: доступ запрещён")
else:
    print("Плоский: доступ разрешён")

# Цепочное сравнение вместо and
temperature = 23
if 18 <= temperature <= 26:
    print("Комфортная температура (цепочное сравнение)")

age = 8
is_child = 0 <= age < 18
print("is_child:", is_child)
# Вложенный: доступ запрещён
# Плоский: доступ запрещён
# Комфортная температура (цепочное сравнение)
# is_child: True

Что происходит: оба варианта дают одинаковый результат «доступ запрещён», но плоский читается без подсчёта отступов. Выражение 18 <= temperature <= 26 — это цепочное сравнение, эквивалент 18 <= temperature and temperature <= 26, только короче.

Пример 5. Тернарный оператор

Для простого выбора между двумя (или несколькими) значениями тернарный оператор компактнее полноценного if.

📄 examples/ternary.py
age = 20
status = "Совершеннолетний" if age >= 18 else "Несовершеннолетний"
print(status)

score = 85
grade = "Отлично" if score > 90 else "Хорошо" if score > 75 else "Удовлетворительно"
print(grade)

n = 7
parity = "чётное" if n % 2 == 0 else "нечётное"
print(f"{n} — {parity}")
# Совершеннолетний
# Хорошо
# 7 — нечётное

Что происходит: вложенный тернарный оператор для grade допустим, но это верхняя граница читаемости — третий уровень вложенности лучше переписать через if-elif-else.

Пример 6. match-case для HTTP-статусов

match-case (Python 3.10+) удобен, когда одно значение нужно сравнить с набором конкретных шаблонов — читается яснее длинной цепочки elif.

📄 examples/http_status.py
def status_message(status):
    match status:
        case 200:
            return "OK"
        case 400:
            return "Bad Request"
        case 401 | 403 | 404:
            return "Client Error"
        case 500 | 502 | 503:
            return "Server Error"
        case _:
            return "Unknown"


for s in (200, 404, 503, 999):
    print(s, "->", status_message(s))
# 200 -> OK
# 404 -> Client Error
# 503 -> Server Error
# 999 -> Unknown
⚠️ Проверить по документации: match-case доступен только с Python 3.10. Убедитесь, что ваша версия поддерживает эту конструкцию — Python Docs — match statement.

Пример 7. Сортировка трёх чисел: сравнения против sorted()

Задача из практикума 09: научиться выражать порядок через сравнения, а не только вызывать готовую функцию.

📄 examples/sort_three.py
a, b, c = 7, 2, 5

# Вручную через сравнения
if a <= b <= c:
    result = (a, b, c)
elif a <= c <= b:
    result = (a, c, b)
elif b <= a <= c:
    result = (b, a, c)
elif b <= c <= a:
    result = (b, c, a)
elif c <= a <= b:
    result = (c, a, b)
else:
    result = (c, b, a)

print("Вручную:", ", ".join(str(n) for n in result))

# Через встроенную сортировку
print("sorted():", ", ".join(str(n) for n in sorted([a, b, c])))
# Вручную: 2, 5, 7
# sorted(): 2, 5, 7

Что происходит: оба способа дают одинаковый результат. Ручной вариант — тренировка цепочных сравнений и полного перебора вариантов порядка; на практике для реальной сортировки почти всегда используют sorted().

Пример 8. Високосный год: комбинация and/or

Год високосный, если делится на 4, но не на 100, либо делится на 400 — классический пример, где скобки в логическом выражении обязательны.

📄 examples/leap_year.py
for year in (2024, 1900, 2000, 2023):
    is_leap = (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0)
    if is_leap:
        print(f"{year} год является високосным.")
    else:
        print(f"{year} год не является високосным.")
# 2024 год является високосным.
# 1900 год не является високосным.
# 2000 год является високосным.
# 2023 год не является високосным.

Что происходит: 1900 делится на 100, но не на 400 — не високосный. 2000 делится и на 100, и на 400 — снова високосный. Без скобок вокруг and-части приоритет операторов дал бы неверный результат для части годов.

Пример 9. Встроенные математические функции и банковское округление

abs, max, min, pow, sum, round работают без импорта — это первый слой математики Python.

📄 examples/builtin_math.py
print(abs(-7))
print(max(1, 5, 3))
print(min(2, 8, 4, 1))
print(pow(2, 3))
print(sum([1, 2, 3, 4]))
print(round(4.567, 2))

# Банковское округление: до ближайшего чётного при дробной части 0.5
print(round(1.5), round(2.5), round(3.5), round(-1.5), round(-2.5))
# 7
# 5
# 1
# 8
# 10
# 4.57
# 2 2 4 -2 -2

Что происходит: round(2.5) дал 2, а не 3 — это стандарт IEEE 754 «округление до чётного», а не ошибка Python. Для школьного округления «всегда от нуля» нужен отдельный алгоритм (пример 10).

Пример 10. Модуль math: корни, факториал, округления, гипотенуза

Когда встроенных функций не хватает, подключают math: корни, факториал, округление вверх/вниз, константы. Здесь же — практическое применение в теореме Пифагора и в математическом округлении «от нуля».

📄 examples/math_module.py
import math

print(math.sqrt(25))
print(math.factorial(5))
print(math.ceil(4.2), math.floor(4.9))
print(round(math.pi, 4), round(math.e, 4))

a_leg, b_leg = 3.0, 4.0
hypotenuse = math.sqrt(a_leg ** 2 + b_leg ** 2)
print(f"Гипотенуза: {hypotenuse}")


def round_half_away_from_zero(x):
    frac = x - int(x)
    if x >= 0:
        return math.ceil(x) if frac >= 0.5 else math.floor(x)
    return math.floor(x) if frac <= -0.5 else math.ceil(x)


for value in (2.5, -2.5, 2.4, -2.4):
    print(value, "->", round_half_away_from_zero(value))
# 5.0
# 120
# 5 4
# 3.1416 2.7183
# Гипотенуза: 5.0
# 2.5 -> 3
# -2.5 -> -3
# 2.4 -> 2
# -2.4 -> -2

Что происходит: катеты 3 и 4 дают гипотенузу ровно 5.0 — классическая пифагорова тройка. Функция round_half_away_from_zero использует math.ceil для положительной половины и math.floor для отрицательной, поэтому 2.5 и -2.5 округляются симметрично от нуля, в отличие от встроенного round() из примера 9.

Пример 11. Три способа импорта модуля

Модуль — обычный файл .py. Импортировать его можно целиком, частично или с псевдонимом — от выбора зависит, как потом обращаться к функциям.

📄 examples/import_styles.py
import math
print(math.sqrt(16))

from math import sqrt, pi
print(sqrt(16), round(pi, 4))

import math as m
print(m.sqrt(16))
# 4.0
# 4.0 3.1416
# 4.0

Что происходит: все три способа дают один и тот же результат 4.0, но по-разному называют функцию: math.sqrt, просто sqrt или m.sqrt. from math import * тоже сработает, но не рекомендуется — импортирует все имена сразу и рискует затереть уже существующие переменные (например, свою pi).

Пример 12. Точность float и Decimal в денежном расчёте

Финальный пример объединяет тему хранения чисел с практической задачей: посчитать сумму со скидкой так, чтобы копейки не «поплыли».

📄 examples/float_vs_decimal.py
import math
from decimal import Decimal

a = 0.1 + 0.2
print(a)
print(a == 0.3)
print(math.isclose(a, 0.3))

price = 19.99
quantity = 100
discount = 0.20 if quantity >= 100 else 0.0
total_float = price * quantity * (1 - discount)
print(f"float: {total_float}")

price_d = Decimal("19.99")
discount_d = Decimal("0.20")
total_decimal = price_d * quantity * (1 - discount_d)
print(f"Decimal: {total_decimal}")

# Неправильно: float уже внёс погрешность до Decimal
print(Decimal(0.1) + Decimal(0.2))
# 0.30000000000000004
# False
# True
# float: 1599.1999999999998
# Decimal: 1599.2000
# 0.3000000000000000166533453694

Что происходит: 0.1 + 0.2 == 0.3 ложно из-за двоичного представления float, а math.isclose сравнивает безопасно. Расчёт суммы на float дал «грязный» хвост 1599.1999999999998, а Decimal со строковыми литералами — ровно 1599.2000. При этом Decimal(0.1) (без кавычек) уже наследует погрешность float — строку нужно передавать всегда.