Приведение типов и ввод
Теория
Всё, что приходит в программу снаружи — из формы на сайте, из URL, из файла, из переменной окружения или с клавиатуры через input(), — приходит строкой. Даже если пользователь ввёл 3, программа получит "3". Прежде чем считать, сравнивать или сохранять, строку нужно привести к нужному типу: int(), float(), Decimal(), bool(), а обратно — str().
Приведение — точка, где чаще всего ломаются программы. Не каждую строку можно превратить в число: int("3 шт") выбросит ValueError. А некоторые преобразования работают, но не так, как ожидаешь: bool("False") — это True, а int(3.9) — это 3. В этой теме — какие преобразования есть, где они падают и где молча делают не то.
Наглядно
Таблица 1. Как работают преобразования: что получится и на что обратить внимание.
| Выражение | Результат | Комментарий |
|---|---|---|
int("3") |
3 |
строка из цифр → целое |
int(" 3 ") |
3 |
пробелы по краям допустимы |
int("3 шт") |
ValueError |
лишние символы — ошибка |
int("2.0") |
ValueError |
int() не разбирает дробную запись |
int(3.9) |
3 |
из float дробная часть отбрасывается, не округляется |
float("1499.90") |
1499.9 |
строка → дробное (неточно, для денег не годится) |
Decimal("1499.90") |
Decimal('1499.90') |
строка → точное десятичное |
str(1042) |
"1042" |
любое значение → строка |
bool("") |
False |
пустая строка — ложь |
bool("False") |
True |
любая непустая строка — истина |
bool(0) |
False |
ноль — ложь |
На практике
Задача: обработать данные формы оформления заказа — количество, цену, флаг «подарочная упаковка» — и не сломаться на кривом вводе.
Шаг 1. Получаем данные формы
Данные формы — всегда строки. В тренажёре ввод с клавиатуры (input()) заменяем переменными — суть та же:
quantity = "3" # то же самое вернул бы input("Количество: ") price = "1499.90" gift_wrap = "false" print(type(quantity), type(price), type(gift_wrap))
Результат:
<class 'str'> <class 'str'> <class 'str'>
Шаг 2. Превращаем в числа
Количество — в int, цену — в Decimal (не во float: это деньги):
from decimal import Decimal qty = int(quantity) unit_price = Decimal(price) print(qty * unit_price)
Результат:
4499.70
Шаг 3. Превращаем число в строку
Для склейки число превращают в строку через str() — но f-строка делает это сама и читается лучше:
order_id = 1042 print("Заказ №" + str(order_id)) print(f"Заказ №{order_id}")
Результат:
Заказ №1042 Заказ №1042
Шаг 4. Встречаем ошибку преобразования
Покупатель ввёл в поле количества «3 шт»:
int("3 шт")
Результат:
ValueError: invalid literal for int() with base 10: '3 шт'
Программа упала. Перехватывать такие ошибки и показывать пользователю понятное сообщение научимся в разделе «Исключения»; пока важно знать, что int() и float() на кривом вводе падают с ValueError.
Шаг 5. Помним, что int() отбрасывает дробь
int() от дробного числа не округляет, а отрезает дробную часть:
print(int(3.9), int(-3.9), round(3.9))
Результат:
3 -3 4
Если нужно округление — round() (или Decimal.quantize для денег).
Шаг 6. Разбираем логические значения
Флаг из формы пришёл строкой "false". Наивное bool() даёт неожиданный ответ:
print(bool("false"), bool("False"), bool("")) print(gift_wrap.lower() == "true")
Результат:
True True False False
bool() от строки проверяет только «пустая или нет». Строку-флаг сравнивают с ожидаемым значением явно.
Частые ошибки
- Расчёт со строкой.
"3" * 1499— строка из 1499 троек,"1499" + "1499"—"14991499". Сначала приводим тип. bool("False"). Любая непустая строка —True. Флаги из форм сравнивают явно:value.lower() == "true".int("2.0").int()не разбирает запись с точкой —ValueError. Если такое возможно:int(float(value))илиDecimal(value).int()вместо округления.int(2.99)—2. Для округления —round().- Деньги через
float.Decimal(float("1499.90"))тянет неточностьfloat. Строку — сразу вDecimal.
Итог
Откуда строки
- Формы, URL, файлы, переменные окружения,
input()— всегдаstr.
Преобразования
int(s),float(s),Decimal(s),str(x),bool(x).int(" 3 ")работает,int("3 шт")иint("2.0")—ValueError.int(3.9) == 3— отбрасывание, не округление.
Логика
bool(): пустая строка,0,None—False; всё остальное —True, включая"False"и"0".- Строку-флаг сравниваем явно:
s.lower() == "true".
Деньги
- Строку цены — сразу в
Decimal, минуяfloat.
Вопросы на собеседовании
Что вернёт bool("False") и почему?
True. Для строк bool проверяет только пустоту: пустая строка ложна, любая непустая — истинна, независимо от содержимого.
Чем int(3.9) отличается от round(3.9)?
int отбрасывает дробную часть (усекает к нулю): int(3.9) == 3, int(-3.9) == -3. round округляет к ближайшему: round(3.9) == 4.
Почему данные из запроса нужно приводить и проверять?
HTTP передаёт текст, поэтому все параметры приходят строками. Без приведения расчёты дают неверный результат или падают, а без проверки пользователь может прислать что угодно — от "3 шт" до отрицательного количества. В Django и DRF эту работу делают формы и сериализаторы.