Как Python конвертирует байты в float?

У меня есть следующий фрагмент кода:

#!/usr/bin/env python3

print(float(b'5'))

Какой печатает 5.0 без ошибок (в Linux с кодировкой utf-8). Я очень удивлен, что это не дает ошибки, поскольку Python не должен знать, какая кодировка используется для объекта bytes.

Любое понимание?

Ответ 1

При передаче объекта bytes float() обрабатывает содержимое объекта как байты ASCII. Этого достаточно здесь, поскольку преобразование из строки в float допускает только цифры ASCII и буквы плюс . и _ любом случае (единственными кодовыми точками, отличными от ASCII, которые будут разрешены, являются непрозрачные кодовые точки), и это аналогично тому, как int() обрабатывает ввод bytes.

Под капотом реализация выполняет следующее:

  • потому что вход не является строкой, на PyNumber_Float() (для объектов str код перескакивает прямо в PyFloat_FromString).
  • PyNumber_Float() проверяет метод __float__, но если он недоступен, он вызывает PyFloat_FromString()
  • PyFloat_FromString() принимает не только объекты str, но и любой объект, реализующий буферный протокол. Имя String является удержанием Python 2, тип str Python 3 называется Unicode в реализации C.
  • bytes реализуют буферный протокол, а макрос PyBytes_AS_STRING используется для доступа к внутреннему буфере C, содержащему байты.
  • Комбинация двух внутренних функций с именем _Py_string_to_number_with_underscores() и float_from_string_inner() затем используется для анализа ASCII-байтов в значение с плавающей запятой.

Для реальных str строк реализация CPython фактически преобразует любую строку, отличную от ASCII, в последовательность байтов ASCII, только просматривая кодовые точки ASCII во входном значении и преобразуя любой символ пробела без ASCII в ascii 0x20 пробелов, чтобы затем использовать тот же самый _Py_string_to_number_with_underscores()/float_from_string_inner().

Я вижу это как ошибку в документации и подал проблему с проектом Python, чтобы обновить его.