Python 中字节文字的比较

问题描述 投票:0回答:4

出现以下问题是因为我试图使用

bytes
字符串作为字典键,而我理解为相等的字节值并未被视为相等。

为什么以下 Python 代码比较不相等 - 这两个不是相同二进制数据的等效表示(该示例是故意选择的以避免字节序)?

b'0b11111111' == b'0xff'

我知道以下评估结果为真,证明了等价性:

int(b'0b11111111', 2) == int(b'0xff', 16)

但是为什么 Python 强迫我知道表示形式呢?与字节顺序有关吗?除了将它们全部转换为例如十六进制文字之外,是否有一些简单的方法可以强制它们比较等效值?是否有一种透明且清晰的方法可以以(某种程度上)独立于平台的方式在所有表示之间移动(或者我要求太多)?

假设我实际上想使用 8 位以

b'0b11111111'
的形式对字典进行索引,那么为什么 Python 将其扩展为 10 个字节以及如何防止这种情况发生?

这是大型树数据结构的一小部分,将索引扩展 80 倍似乎是对内存的巨大浪费。

python comparison byte endianness radix
4个回答
17
投票

字节可以代表任意数量的事物。 Python 不能也不会猜测你的字节可能编码的内容。

例如,

int(b'0b11111111', 34)
也是一个有效的解释,但该解释不等于十六进制FF。

事实上,解释的数量是无穷无尽的。这些字节可以表示一系列 ASCII 代码点、图像颜色或音符。

在您明确应用解释之前,字节对象仅由 0-255 范围内的值序列组成,并且这些字节的文本表示形式使用 ASCII(如果可表示为可打印文本): >>> list(bytes(b'0b11111111')) [48, 98, 49, 49, 49, 49, 49, 49, 49, 49] >>> list(bytes(b'0xff')) [48, 120, 102, 102]

那些字节序列不相等。

如果您想将这些序列显式解释为整数文字,请使用

ast.literal_eval()

 来解释 
decoded 文本值;在比较之前始终先标准化: >>> import ast >>> ast.literal_eval(b'0b11111111'.decode('utf8')) 255 >>> ast.literal_eval(b'0xff'.decode('utf8')) 255



7
投票
b'0b11111111'

由10个字节组成:


In [44]: list(b'0b11111111') Out[44]: ['0', 'b', '1', '1', '1', '1', '1', '1', '1', '1']

b'0xff'

由 4 个字节组成:


In [45]: list(b'0xff') Out[45]: ['0', 'x', 'f', 'f']

显然,它们不是同一个对象。

Python 重视明确性。 (

显式优于隐式

。)它并不假设b'0b11111111'必然是整数的二进制表示。它只是一串字节。必须明确说明您选择如何解释它。

    


4
投票
0b11111111

(或 255)的字节字符串。这不是

b'0b11111111'
所做的 – 它实际上代表表示
character
(Unicode) 字符串 '0b11111111' 的字节字符串。

你想要的就写成

b'\xff'

。您可以检查它实际上是一个字节:

len(b'\xff') == 1

要将 Python

int

转换为二进制表示形式,您可以使用

ctypes
 库。您需要选择一种 C 整数类型,例如:
>>> bytes(ctypes.c_ubyte(255)) b'\xff' >>> bytes(ctypes.c_ubyte(0xff)) b'\xff' >>> bytes(ctypes.c_long(255)) b'\xff\x00\x00\x00\x00\x00\x00\x00'

注意:您可以分别使用别名 
c_ubyte

(即 8 位无符号 C 整数)和

c_long
(64 位有符号 C 整数)来代替
c_uint8
c_int64

转换回来:

>>> ctypes.c_ubyte.from_buffer_copy(b'\xff').value 255

小心溢出:

>>> ctypes.c_ubyte(256) c_ubyte(0)



0
投票
byte

类型。您有

bytes
bytearray
,分别用于可变和不可变数据。
这意味着虽然 

0b1111_1111

0xff
代表相同的整数值 255,但使用
b'0b1111_1111'
只是一串 ASCII 字符,在本例中为 11 个字符。
但也许,你的意思更多的是:

>>> bytes([0xff]) b'\xff' >>> bytes([0b1111_1111]) b'\xff' >>> bytes([0xff]) == bytes([0b1111_1111]) True

	
© www.soinside.com 2019 - 2024. All rights reserved.