Приведение типов и ввод

Теория

Всё, что приходит в программу снаружи — из формы на сайте, из 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()) заменяем переменными — суть та же:

python
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: это деньги):

python
from decimal import Decimal

qty = int(quantity)
unit_price = Decimal(price)
print(qty * unit_price)

Результат:

вывод
4499.70

Шаг 3. Превращаем число в строку

Для склейки число превращают в строку через str() — но f-строка делает это сама и читается лучше:

python
order_id = 1042
print("Заказ №" + str(order_id))
print(f"Заказ №{order_id}")

Результат:

вывод
Заказ №1042
Заказ №1042

Шаг 4. Встречаем ошибку преобразования

Покупатель ввёл в поле количества «3 шт»:

python
int("3 шт")

Результат:

вывод
ValueError: invalid literal for int() with base 10: '3 шт'

Программа упала. Перехватывать такие ошибки и показывать пользователю понятное сообщение научимся в разделе «Исключения»; пока важно знать, что int() и float() на кривом вводе падают с ValueError.

Шаг 5. Помним, что int() отбрасывает дробь

int() от дробного числа не округляет, а отрезает дробную часть:

python
print(int(3.9), int(-3.9), round(3.9))

Результат:

вывод
3 -3 4

Если нужно округление — round() (или Decimal.quantize для денег).

Шаг 6. Разбираем логические значения

Флаг из формы пришёл строкой "false". Наивное bool() даёт неожиданный ответ:

python
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 эту работу делают формы и сериализаторы.

Ошибка в тексте

Сообщить об ошибке могут зарегистрированные пользователи — так в сообщениях меньше спама.

Войти, чтобы сообщить