Python 输出奇怪的字节数组

Python outputs strange bytearray

Python 有时会生成奇怪的神秘字节数组。我不知道如何解释它们。

考虑以下示例。

import struct
floats = [3.14, 2.7, 0.0, -1.0, 1.1]
s = struct.pack('f'*len(floats), *floats)
print("The bytes:")
print(s)

struct.pack 函数应该输出列表中每个值的 'bytes-representation'。该列表由 64 位浮点数组成(我的计算机是 64 位),所以我希望每个浮点数都由 8 个字节表示:

 3.14 -> 0x40 0x09 0x1E 0xB8 0x51 0xEB 0x85 0x1F
 2.7  -> 0x40 0x05 0x99 0x99 0x99 0x99 0x99 0x9A
 0.0  -> 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
-1.0  -> 0xBF 0xF0 0x00 0x00 0x00 0x00 0x00 0x00
 1.1  -> 0x3F 0xF1 0x99 0x99 0x99 0x99 0x99 0x9A

顺便说一句,我使用以下网站进行了正确的转换:http://babbage.cs.qc.cuny.edu/IEEE-754.old/Decimal.html

不幸的是,Python 没有输出我期望的那些字节。相反,Python 输出一些非常神秘的字节列表。但这真的是一个字节列表吗? Python 输出的东西很奇怪:

b'\xc3\xf5H@\xcd\xcc,@\x00\x00\x00\x00\x00\x00\x80\xbf\xcd\xcc\x8c?'

请帮助我理解 Python 在这里做什么。

编辑

显然我应该使用 'd' 而不是 'f',因为我在我的机器上使用双精度浮点数。谢谢先生。 Rad Lexus 为您解答。但是我对 Python 的输出还是有点不解。让我澄清一下。

我从你给我的以下代码开始:

import struct
floats = [3.14, 2.7, 0.0, -1.0, 1.1]
s = []
for f in floats:
    s.append(struct.pack('d', f))

在继续之前,我检查了对象 s 以了解发生了什么。这是我从 s:

得到的
>>> s
[ b'\x1f\x85\xebQ\xb8\x1e\t@', 
  b'\x9a\x99\x99\x99\x99\x99\x05@',
  b'\x00\x00\x00\x00\x00\x00\x00\x00', 
  b'\x00\x00\x00\x00\x00\x00\xf0\xbf',
  b'\x9a\x99\x99\x99\x99\x99\xf1?'     ]

s 中的某些条目长度为 8 个字节。这就是我所期望的。但有些条目更短。无论如何,没有条目给出相应浮点数的正确 8 字节表示 - 除了浮点 0.0.

您的代码继续使用一些魔法来提取每个浮点数实际正确的 8 个字节:

print("The bytes:")
for floatInHex in s:
    for byteval in floatInHex:
        print ('%02x' % byteval, end="")

现在我们得到了正确的结果。但是为什么 s 对象还没有包含每个浮点数的正确 8 字节呢?为什么需要这种额外的魔法?


>>> binascii.hexlify(struct.pack('>d', floats[0]))
b'40091eb851eb851f'

>>> import struct
>>> import binascii
>>>
>>> floats = [3.14, 2.7, 0.0, -1.0, 1.1]
>>> s = struct.pack('>' + 'd'*len(floats), *floats)
>>> binascii.hexlify(s)
b'40091eb851eb851f400599999999999a0000000000000000bff00000000000003ff199999999999a'

如果你想分别得到每个float表示,你需要对它们进行迭代和转换。 (使用循环或列表理解,..)

>>> for f in floats:
...     print(' '.join('0x{:02x}'.format(c) for c in struct.pack('>d', f)))
...
0x40 0x09 0x1e 0xb8 0x51 0xeb 0x85 0x1f
0x40 0x05 0x99 0x99 0x99 0x99 0x99 0x9a
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0xbf 0xf0 0x00 0x00 0x00 0x00 0x00 0x00
0x3f 0xf1 0x99 0x99 0x99 0x99 0x99 0x9a

您想解包为 double,但在程序中您使用 float 的说明符:f。这就是你得到的:

c3 f5 48 40 for 3.14

(请参阅 python struct pack double 了解为什么您会看到一些 ASCII 字符。)

此代码将为每个数字打印一行十六进制:

import struct
floats = [3.14, 2.7, 0.0, -1.0, 1.1]
s = []
for f in floats:
    s.append(struct.pack('d', f))
print("The bytes:")
for floatInHex in s:
  for byteval in floatInHex:
    print ('%02x' % byteval, end=""),
  print ()

结果:

The bytes:
1f85eb51b81e0940
9a99999999990540
0000000000000000
000000000000f0bf
9a9999999999f13f

Python 正在输出 "strange" 打印行为,因为 print 函数将尝试将任何 ASCII 可打印字符打印为 ASCII,不是十六进制。

使用 binascii 可以正确打印,因为 从不 打印 ASCII 字符,仅打印十六进制字符。

我也被骗了!正要问同样的问题,然后在这里找到这个: Python Bytearray Printing