Числовые ошибки и отладка
Девять коротких лабораторий — от настоящих исключений до валидных, но неожиданных числовых результатов.
Собрали девять коротких лабораторий — часть из них про настоящие ошибки с исключением, часть — про валидный, но неожиданный числовой результат. Важно уметь отличать эти два сценария.
ValueError
TypeError
print(10 / 2)
Наблюдение: результат — 5.0, а не 5.
Объяснение: оператор / в Python ВСЕГДА возвращает float (раздел 4.7), даже при делении нацело.
print(int(3.99))
Наблюдение: результат — 3, а не 4.
Объяснение: int() отбрасывает дробную часть (усечение к нулю), а не округляет (раздел 4.16).
print(0.1 + 0.2 == 0.3)
Наблюдение: результат — False.
Объяснение: float хранит приближение (раздел 4.11) — используйте math.isclose() вместо ==.
from decimal import Decimal
print(Decimal(0.1))
Наблюдение: результат — длинная некруглая дробь, а не 0.1.
Объяснение: аргумент — float, а значит приближение из раздела 4.11 уже произошло ДО создания Decimal. Используйте Decimal("0.1").
print(7 // 3)
print(7 / 3)
Наблюдение: 2 против 2.333....
Объяснение: // — целочисленное деление (отбрасывает дробную часть результата), / — обычное деление, всегда float.
print(-7 // 3)
print(-7 % 3)
Наблюдение: -3 и 2 — не то, что многие ожидают.
Объяснение: // округляет к минус бесконечности, а не к нулю (раздел 4.7).
print(int("FF"))
Наблюдение: ValueError: invalid literal for int() with base 10: 'FF'
Объяснение: без указания основания int() ожидает десятичную запись. Нужно: int("FF", 16).
price = 100
quantity = 0
print(price / quantity)
Наблюдение: ZeroDivisionError: division by zero.
Объяснение: перед делением стоит проверить делитель на ноль, если он может быть нулевым — подробно про условия будет в следующей главе; здесь достаточно узнать сам тип ошибки.
# Задача: посчитать точную сумму чека в рублях и копейках
Наблюдение: float способен дать погрешность в дробных суммах.
Объяснение: для денег правильный выбор — Decimal (раздел 4.14), а не float.