Python如何将字节转换为浮点数?

16

我有以下代码片段:

#!/usr/bin/env python3

print(float(b'5'))
在Linux上使用utf-8编码,以下哪个会打印5.0而不会出错?我很惊讶它没有报错,因为Python不应该知道bytes对象使用了什么编码方式。
有什么见解吗?

1
你有读过这份文档和这个链接吗?https://docs.python.org/3.6/c-api/buffer.html#bufferobjects - Mazdak
4
float() 的文档显示它可以接受一个字符串、一个数字或者一个实现了 __float__ 方法的类型。bytes 没有实现 __float__ 方法。 - Martijn Pieters
@MartijnPieters 在这里提到,如果参数是一个字符串,它应该包含一个十进制数,可选地带有符号,并可选地嵌入空格。b'5'不遵循这个规则吗?虽然这应该在文档中明确说明。 - Mazdak
2
这是一个合理的问题,因为并非所有编码都是ASCII的超集。 - PM 2Ring
2
@Kasramvd:不,它不是。bytes类型不被视为字符串。 - Martijn Pieters
@MartijnPieters 确实,我是指由于字节表示字符序列并且它们也可以包含小数,因此应该也提到了这一点,正如您所提到的,这是文档中的一个错误。 - Mazdak
1个回答

13
当传入一个bytes对象时,float()函数将把该对象的内容视为ASCII字节。这在这里已经足够了,因为从字符串到浮点数的转换只接受ASCII数字和字母,以及._(唯一允许的非ASCII码点是空格码点),而这与int()函数处理bytes输入的方式类似。
在底层实现中,它会执行以下操作:
  • 由于输入不是字符串,因此在对象上调用PyNumber_Float()方法(对于str对象,代码直接跳转到PyFloat_FromString函数)。
  • PyNumber_Float()检查是否存在__float__方法,但如果该方法不存在,则调用PyFloat_FromString()函数。
  • PyFloat_FromString()不仅接受str对象,还接受实现缓冲区协议的任何对象。在Python 2中,String名称是保留的,而在C实现中,Python 3的str类型称为Unicode
  • bytes对象实现了缓冲区协议,并使用PyBytes_AS_STRING来访问保存字节的内部C缓冲区。
  • 然后使用两个名为_Py_string_to_number_with_underscores()float_from_string_inner()的内部函数组合将ASCII字节解析为浮点值。

对于实际的str字符串,CPython实现实际上会通过仅查看输入值中的ASCII码点并将任何非ASCII空格字符转换为ASCII 0x20空格的方式将任何非ASCII字符串转换为ASCII字节序列,然后使用相同的_Py_string_to_number_with_underscores() / float_from_string_inner()组合。

我认为这是文档中的错误,并已向Python项目提交了问题报告以进行更新。


1
我知道这个人关于Python的东西应该什么都知道。 - Sraw
感谢您的出色回答。那么,为了明确起见,这将在某些编码(例如UTF-16)下失败吗? - static_rtti
2
@static_rtti:完全正确,因为\x00字节不会被接受。这些字节必须是ASCII码,并符合float()字符串解释规则。 - Martijn Pieters

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接