Python struct.pack несовместим

Я использую struct.pack, чтобы вернуть мне объект bytes. Однако это непоследовательно.

print(struct.pack('BbbB', 0x1B, -2, 1, 0)) #returns b'\x1b\xfe\x01\x00' GOOD
print(struct.pack('BbbB', 0x0F, -2, 1, 0)) #returns b'\x0f\xfe\x01\x00' GOOD
print(struct.pack('BbbB', 0x0C, -2, 1, 0)) #returns b'\x0c\xfe\x01\x00' GOOD
print(struct.pack('BbbB', 0x35, -2, 1, 0)) #returns b'5\xfe\x01\x00'    ???
print(struct.pack('BbbB', 0x21, -2, 1, 0)) #returns b'!\xfe\x01\x00'    ???

Если я посмотрю на таблицу символов ASCII, то пойму, почему она стала "5" а также "!" в последних двух примерах, но разве он не должен был вернуть мне b'\0x35\xfe\x01\x00' и b'\0x21\xfe\x01\x00' вместо этого вышеуказанного результата? Что мне здесь не хватает?

Я использую Python 3.7.0.


person Gabriele    schedule 09.08.2018    source источник


Ответы (2)


Это не пакет, который является непоследовательным. Вас смущает функция печати.

Оба '!' (значение ascii 33, шестнадцатеричное 0x21) и '5' (значение ascii 53, шестнадцатеричное 0x35) являются печатными символами, поэтому они просто печатаются нормально. Однако другие байты не печатаются, поэтому python прибегает к печати их шестнадцатеричного представления, чтобы вы могли хотя бы увидеть что-то, имеющее смысл.

Значения байтов - это то, что вы ожидаете, не волнуйтесь.

person alkanen    schedule 09.08.2018
comment
@juanpa.arrivillaga, я не уверен, как ваш комментарий относится к моему ответу? - person alkanen; 09.08.2018
comment
Это был ответ на уже удаленный комментарий ОП. - person juanpa.arrivillaga; 09.08.2018
comment
Ах хорошо. Я никогда не видел этот комментарий. - person alkanen; 09.08.2018

Взгляните на это:

>>> b'\x35\xfe\x01\x00'
b'5\xfe\x01\x00'
>>> b'\x35\xfe\x01\x00' == b'5\xfe\x01\x00'
True
>>> b'\x35'
b'5'
>>> b'\x35' == b'5'
True
>>> b'\x35'[0]
53
>>> b'5'[0]
53

И b'\x35', и b'5' имеют одинаковое значение байта 0x35. Просто они оба являются двумя разными представлениями одного и того же значения.

Очень часто существует несколько способов записи буквального значения для одного и того же фактического значения. Например, десятичное значение 53 может быть представлено с помощью 53, 0x35, 0o65 или 0b110101. Это все числовые литералы для одного и того же объекта int.

Точно так же b'\x35 и b'5' — это всего лишь два литерала строки байтов для одного и того же объекта байтов.

Когда вы печатаете объекты, Python внутренне вызывает str() для объектов, чтобы убедиться, что объекты можно распечатать. Для объектов bytes это означает, что возвращается строковый литерал bytes. И поскольку существует несколько способов представления этого объекта, Python должен выбрать одно представление.

Для байтов правило заключается в том, что всякий раз, когда байт может быть представлен как печатный символ ASCII, этот символ используется вместо управляющей последовательности. Как правило, это позволяет вам читать байтовые строки, представляющие данные ASCII. Например, b'foo' намного читабельнее, чем b'\x66\x6f\x6f' (но означает одно и то же).

Если вам нужно получить согласованное строковое представление объекта bytes, вы можете явно преобразовать его в шестнадцатеричную строку. Например, позвонив по номеру bytes.hex:

>>> b'5\xfe\x01\x00'.hex()
'35fe0100'

Конечно, теперь это уже не двоичные данные, а строка, представляющая двоичные данные, закодированные как шестнадцатеричная строка. Если вы хотите на самом деле передать данные, например, по сети или внутри файла, вы захотите сохранить его как объект bytes и просто использовать его.

person poke    schedule 09.08.2018