Почему я получаю int, когда индексирую байты?

#python #python-3.x #list #unicode

Вопрос:

Я пытаюсь получить первый символ байтовой строки в python 3.4, но когда я его индексирую, я получаю int :

 >>> my_bytes = b'just a byte string'
b'just a byte string'
>>> my_bytes[0]
106
>>> type(my_bytes[0])
<class 'int'>
 

Мне это кажется неинтуитивным, как я и ожидал b'j' .

Я обнаружил, что могу получить ту ценность, которую ожидаю, но для меня это похоже на взлом.

 >>> my_bytes[0:1]
b'j'
 

Может кто-нибудь, пожалуйста, объяснить, почему это происходит?

Комментарии:

1. Взлом с использованием такого диапазона my_bytes[0:1] действительно помог мне написать код, совместимый с Python2/Python3. Я хотел бы увидеть ответ, который охватывает наилучшую практику для совместимого кода, решающего эту проблему. Например: ord(my_bytes[0]) дает int в Python2, но my_bytes[0] дает int в Python3. Чтобы работать в обоих, я использую ord(my_bytes[0:1]) то, что кажется действительно уродливым для Python3.

2. ваш ответ помог мне, я не смог найти наилучшего подхода к работе с байтами и избежать преобразования целых чисел при доступе к индексу, спасибо.

3. Я заметил те же явления со списками, составленными из bytearray и bytestring. type(list(b'abctest').pop(0)) дать <class 'int'> . type(list(bytearray(b'abctest')).pop(0)) дать <class 'int'> . type(bytearray(b'abctest').pop(0)) дать <class 'int'> .

Ответ №1:

Тип является bytes типом двоичной последовательности и явно задокументирован как содержащий последовательность целых чисел в диапазоне от 0 до 255.

Из документации:

Объекты Bytes-это неизменяемые последовательности отдельных байтов.

[…]

В то время как байтовые литералы и представления основаны на тексте ASCII, байтовые объекты фактически ведут себя как неизменяемые последовательности целых чисел, при этом каждое значение в последовательности ограничено таким образом, что 0 <= x < 256 [.]

[…]

Поскольку объекты bytes являются последовательностями целых чисел (сродни кортежу), для объекта bytes b b[0] будет целым числом , в то время b[0:1] как будет bytes объектом длины 1. (Это контрастирует с текстовыми строками, где как индексирование, так и нарезка приведут к строке длиной 1).

Смелый акцент мой. Обратите внимание, что индексирование строки является небольшим исключением среди типов последовательностей; 'abc'[0] дает вам str объект длиной один; str является единственным типом последовательности, который всегда содержит элементы своего собственного типа.

Это перекликается с тем, как другие языки обрабатывают строковые данные; в C unsigned char тип также фактически является целым числом в диапазоне 0-255. Многие компиляторы языка Си по умолчанию unsigned используют, если вы используете неквалифицированный char тип, а текст моделируется как char[] массив.

Комментарии:

1. «в то время как b[0:1] будет байтовым объектом длиной 1(это контрастирует с текстовыми строками, где как индексирование, так и нарезка приведут к строке длиной 1)»не могли бы вы, пожалуйста, объяснить это предложение, которое я не понял?

2. @CY5: извините, какую часть вы получили? Если вы создадите строку (в Юникоде), 'abc'[0]' будет создан другой строковый объект 'a' . Если вы используете тот же срез, что и в примере, используемом для bytes объекта, 'abc'[0:1] также создается строковый объект длиной один, 'a' .

3. @CY5: но для bytes объекта b'abc'[0] создается целое число ( 97 ), а нарезка создает bytes объект длиной один ( b'abc'[0:1] производит b'a' ).