ValueError в Python: разбор строк в числа
int('восемнадцать') — тип подходящий, а значение не помещается. Разбираем сообщение invalid literal, границы int и float и честную проверку isdigit.
Редакция Питоники
Данные из файлов, форм и API приходят строками, и первым делом их превращают в числа: int('17'), float('3.14'). Разбор ломается на живом вводе регулярно — пользователь набрал словами, файл пришёл с пустой строкой. Третий урок курса уже ловил эту ошибку в ветке except ValueError; теперь разберёмся, когда именно она возникает и что говорит её сообщение.
Разбор строки, которая не число
age_text = 'восемнадцать'
age = int(age_text)
Ошибка ValueError означает, что тип операции подходящий, а значение в него не помещается. Сравните с TypeError из мира несоответствий: там операция вообще не применима к такому типу, а здесь int со строками работает — просто из этой конкретной строки число не извлекается. Формулировка invalid literal означает «неверный литерал»: запись числа не выдержана.
Перебираем грязный ввод
for text in ['17', 'восемнадцать', '']:
try:
print(repr(text), '->', int(text))
except ValueError as e:
print(repr(text), '->', type(e).__name__, '-', str(e))
'17' -> 17 'восемнадцать' -> ValueError - invalid literal for int() with base 10: 'восемнадцать' '' -> ValueError - invalid literal for int() with base 10: ''
Функция repr печатает строку в кавычках — удобно видеть, что именно разбиралось, особенно пустую строку, которая на экране выглядит как ничего. Сообщение ValueError в каждой ветке называет виновника: и слово словами, и пустота дают одну и ту же ошибку с разным значением внутри. int() строг к содержимому: пробелы по краям он прощает, но дробную запись и лишние слова не примет.
for text in [' 42 ', '42.5', '4 2']:
try:
print(repr(text), '->', int(text))
except ValueError as e:
print(repr(text), '->', type(e).__name__, '-', str(e))
' 42 ' -> 42 '42.5' -> ValueError - invalid literal for int() with base 10: '42.5' '4 2' -> ValueError - invalid literal for int() with base 10: '4 2'
Пробелы по краям int обрезает сам, а вот точка — уже не его дело: '42.5' для целого числа неверная запись, даже хотя выглядит числом. Пустая строка между цифрами ломает разбор так же, как слово. Кстати, int('42.5') не округляет: чтобы получить дробное число, нужен float.
for text in ['3.14', 'abc']:
try:
print(repr(text), '->', float(text))
except ValueError as e:
print(repr(text), '->', type(e).__name__, '-', str(e))
try:
int(['1', '2'])
except TypeError as e:
print('список ->', type(e).__name__, '-', str(e))
'3.14' -> 3.14 'abc' -> ValueError - could not convert string to float: 'abc' список -> TypeError - int() argument must be a string, a bytes-like object or a real number, not 'list'
Граница между двумя ошибками видна в одном примере. Строка 'abc' — подходящий тип, неподходящее значение: ValueError. Список — неподходящий тип вовсе: TypeError с внятным перечислением того, что int принимает. Правило простое: ловить нужно ту ошибку, которая реально случится в вашем коде. Разбираете строки — ловите ValueError, а TypeError останется сигналом о баге.
Проверка заранее: isdigit
Второй способ жить с грязным вводом — спросить у строки, число ли она, до вызова int. У строк для этого есть метод isdigit:
candidates = ['123', '42.5', '-7', '', 'восемь']
for text in candidates:
print(repr(text), 'isdigit:', text.isdigit())
'123' isdigit: True '42.5' isdigit: False '-7' isdigit: False '' isdigit: False 'восемь' isdigit: False
Метод строг: только чистые цифры от края до края. Минус цифрой не считается, поэтому '-7' не проходит проверку — хотя int его отлично разбирает. Точка тоже не цифра. Из-за такой строгости isdigit подходит не для всех вводов: возраст со знаком минус, цену с копейками — всё это отсеется.
def safe_int(text, default=0):
if text.isdigit():
return int(text)
return default
print(safe_int('42'))
print(safe_int('восемнадцать'))
print(safe_int('17', default=-1))
42 0 17
Классический каркас: проверка пускает к int только чистые цифры, всё остальное получает умолчание. Удобно, пока ввод заведомо положительные целые. Как только появляются минусы или дроби, проверка начинает отбраковывать годные значения — и тут try с except ValueError честнее: он решает по факту, а не по предположению. Какой стиль выбрать — вопрос из четырнадцатого урока об EAFP.
| Вход | isdigit | int() |
|---|---|---|
| '123' | True | разбирает: 123 |
| '-7' | False | разбирает: -7 |
| '42.5' | False | ValueError |
| '' | False | ValueError |
Разбор ввода — самая разносторонняя тренировка для try и except: строки приходят пустыми, словами, с пробелами и минусами, и каждая форма по-своему проверяется. А когда нужно зафиксировать правило для разработчика, а не для пользователя — пригодится assert из восемнадцатого урока.
Сначала предскажи ответ в голове — это главный навык программиста.
try:
print(int('10') + int('5'))
except ValueError:
print('не разобралось')
for t in ['7', 'семь']:
try:
print(int(t) * 2)
except ValueError:
print('skip:', t)
print('-5'.isdigit())
try:
print(int('-5'))
except ValueError:
print('нет')
1. Почему int('восемнадцать') даёт ValueError, а не TypeError?
2. Что вернёт int(' 42 ')?
3. Что произойдёт при int('42.5')?
4. Какая ошибка возникнет при int(['1', '2'])?
5. Что вернёт '-7'.isdigit()?
6. '²'.isdigit() возвращает True. Что вернёт int('²')?
7. Когда try с except ValueError надёжнее проверки isdigit?
Для списка вводов ['15', 'двадцать', ' 30 '] в цикле напечатай «{repr строки} -> {число}», а если int падает с ValueError — «{repr строки} -> не число». Используй try и except внутри цикла.
Почему int('abc') вызывает ValueError в Python?
int умеет принимать строки — тип операции верный, но из этой строки число не извлекается: запись не соответствует формату целого. Python сообщает ValueError: invalid literal for int() with base 10: 'abc', называя неудачное значение прямо в сообщении.
Урок 3: except ValueError — ловим конкретный типКак проверить строку перед int()?
Методом isdigit: строка проходит проверку, только если целиком состоит из цифр. Но метод строг: '-7' и '42.5' он отбракует, а '²' пропустит зря. Надёжнее оборачивать int в try и ловить ValueError — решение принимается по факту разбора.
Чем ValueError отличается от TypeError?
ValueError — значение неподходящее при верном типе: int('abc'). TypeError — тип не подходит вовсе: int(['1']), int(None). Если разбор строк падает с TypeError, в данные просочился не-строковый объект — это другой баг и другой обработчик.
Урок 18: assert и AssertionErrorint(' 42 ') работает, а int('4 2') — нет. Почему?
int обрезает пробелы только по краям записи: ' 42 ' превращается в '42' и разбирается. Пробел внутри — часть значения, и такая запись для целого числа неверна: ValueError: invalid literal for int() with base 10: '4 2'.
Понравился урок? Сошлитесь на него
«Ошибка ValueError означает, что тип операции подходящий, а значение в него не помещается.»
Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.
Что дальше
Осталось в разделе: 20 из 20. Прогресс хранится в вашем браузере.
Что читать дальше
Исключения · Урок 3
except ValueError: ловим конкретный тип ошибки
Уточняем обработчик: except ValueError ловит только свой тип ошибок. Почему голый except прячет опечатки и как ValueError ведёт себя у int и list.remove.
Исключения · Урок 14
EAFP против LBYL в Python: два стиля проверки
Look Before You Leap — смотри, прежде чем прыгнуть; Easier to Ask Forgiveness than Permission — проще извиниться, чем спросить. Одна задача, два стиля, один вердикт.
Исключения · Урок 18
assert в Python: проверки для разработчика и AssertionError
assert — это заявление: здесь должно быть так. Провал превращается в AssertionError с вашим сообщением, а флаг -O умеет вырезать все проверки разом — поэтому инструмент разработчика, а не валидатор ввода.
Похожие уроки по темам
Подобраны автоматически по пересечению тем и ключевых слов.
Строки · Урок 11
Проверки строки: isdigit, isalpha и валидация ввода
Методы-вопросы: строка состоит только из цифр? только из букв? всё в нижнем регистре? Учимся валидировать ввод пользователя одним вызовом.
python isdigitisdigit python
Datetime · Урок 5
strptime: строка превращается в дату
Лог, форма и таблица присылают даты строками — для вычислений нужен объект. Учим strptime читать строку по шаблону и отличать настоящий формат от почти настоящего.
python преобразование строки в датуstrptime valueerror
Исключения · Урок 1
Что такое исключение: первая ошибка в программе
Первая ошибка в программе: читаем traceback за десять секунд — тип ошибки, место и сообщение. Разбираем четыре типовых падения на живом коде.
python valueerror