байты против байтового массива в Python 2.6 и 3 - PullRequest
20 голосов
/ 16 ноября 2009

Я экспериментирую с bytes против bytearray в Python 2.6. Я не понимаю причину некоторых различий.

A bytes итератор возвращает строки:

for i in bytes(b"hi"):
    print(type(i))

Дает:

<type 'str'>
<type 'str'>

Но итератор bytearray возвращает int s:

for i in bytearray(b"hi"):
    print(type(i))

Дает:

<type 'int'>
<type 'int'>

Почему разница?

Я хотел бы написать код, который будет хорошо транслироваться в Python 3. Итак, ситуация в Python 3 такая же?

Ответы [ 5 ]

25 голосов
/ 16 ноября 2009

В Python 2.6 байты являются просто псевдонимом для str .
Этот «псевдотип» был введен для [частичной] подготовки программ [и программистов!] К конвертации / совместимости с Python 3.0, где существует строгое различие в семантике и использовании для str (которые систематически являются Unicode) и байтов (которые являются массивами). октетов, для хранения данных, но не текста)

Точно так же префикс b для строковых литералов неэффективен в 2.6, но это полезный маркер в программе, который явно обозначает намерение программиста иметь строку как строку данных, а не текстовую строку. Эта информация может затем использоваться конвертером 2to3 или подобными утилитами, когда программа портирована на Py3k.

Вы можете проверить это SO Вопрос для получения дополнительной информации.

11 голосов
/ 13 декабря 2018

Для (как минимум) Python 3.7

Согласно документации:

bytes объекты являются неизменяемыми последовательностями из одного байта

bytearray объекты являются изменяемым аналогом байтовых объектов.

И это в значительной степени все, что касается bytes против bytearray. На самом деле они довольно взаимозаменяемы и разработаны достаточно гибкими, чтобы их можно было смешивать в операциях без ошибок. Фактически, в официальной документации есть целый раздел , посвященный тому, чтобы показать сходство между bytes и bytearray apis.

Некоторые подсказки, почему из документов:

Поскольку многие основные двоичные протоколы основаны на кодировке текста ASCII, байтовые объекты предлагают несколько методов, которые действительны только при работе с ASCII-совместимыми данными и тесно связаны со строковыми объектами множеством других способов.

3 голосов
/ 19 ноября 2009

Я пробовал это на Python 3.0.

В Python 3.0 итератор bytes возвращает int с, а не строки, как это сделал Python 2.6:

for i in bytes(b"hi"):
    print(type(i))

Дает:

<class 'int'>
<class 'int'>

A bytearray итератор также возвращает class 'int' s.

3 голосов
/ 16 ноября 2009

Я не уверен, с какой версии, но bytes на самом деле str, что вы можете увидеть, если сделаете type(bytes(b"hi")) -> <type 'str'>.

bytearray - это изменяемый массив байтов, один конструктор которого принимает строку.

1 голос
/ 31 января 2019

TL; DR

python2.6 + bytes = python2.6 + str = python3.x bytes! = Python3.x str

python2.6 + bytearray = python3.x bytearray

python2.x unicode = python3.x str

Длинный ответ

bytes и str изменили значение в python начиная с python 3.x.

Сначала коротко ответим на ваш вопрос , в python 2.6 bytes(b"hi") - это неизменяемый массив байтов (8-бит или октет). Таким образом, тип каждого byte просто byte, что совпадает с str в Python 2.6+ (однако в Python 3.x это не так)

bytearray(b"hi") снова изменяемый массив байтов. Но когда вы спрашиваете его тип, это int, потому что python представляет каждый элемент bytearray как целое число в диапазоне 0-255 (все возможные значения для 8-битного целого). Однако элемент массива bytes представляется как значение ASCII этого байта.

Например, рассмотрим в Python 2.6 +

>>> barr=bytearray(b'hi')
>>> bs=bytes(b'hi')
>>> barr[0] # python shows you an int value for the 8 bits 0110 1000
104 
>>> bs[0] # python shows you an ASCII value for the 8 bits 0110 1000
'h'
>>> chr(barr[0]) # chr converts 104 to its corresponding ASCII value
'h'
>>> bs[0]==chr(barr[0]) # python compares ASCII value of 1st byte of bs and ASCII value of integer represented by first byte of barr
True

Теперь Python 3.x - это совсем другая история. Как вы могли догадаться, странно, почему литерал str будет означать byte в python2.6 +. Ну этот ответ объясняет, что

В Python 3.x str - это текст в Unicode (который ранее был просто массивом байтов, обратите внимание, что Unicode и байты - это две совершенно разные вещи). bytearray - это массив изменяемых байтов, а bytes - это массив неизменных байтов. Они оба имеют почти одинаковые функции. Теперь, если я снова запускаю тот же код в Python 3.x, вот результат. В Python 3.x

>>> barr=bytearray(b'hi')
>>> bs=bytes(b'hi')
>>> barr[0]
104
>>> bs[0]
104
>>> bs[0]==barr[0] # bytes and bytearray are same thing in python 3.x
True

bytes и bytearray - это то же самое в Python 3.x, за исключением изменчивости.

Что случилось с str, спросите вы? str в Python 3 был преобразован в то, что unicode было в Python 2, и тип unicode был впоследствии удален из Python 3, так как он был избыточным.

Я хотел бы написать код, который будет хорошо транслироваться на Python 3. Итак, такая же ситуация в Python 3?

Это зависит от того, что вы пытаетесь сделать. Вы имеете дело с байтами или с ASCII представлением байтов?

Если вы имеете дело с байтами , то я советую использовать bytearray в Python 2, то же самое в Python 3. Но вы теряете неизменность, если это важно для вас.

Если вы имеете дело с ASCII или текстом , то представьте свою строку как u'hi' в Python 2, что имеет то же значение в Python 3. 'u' имеет особое значение в Python 2, который инструктирует python 2 обрабатывать строковый литерал как тип unicode. 'u' в Python 3 не имеет смысла, потому что все строковые литералы в Python 3 по умолчанию являются Unicode (который в смежных целях называется str type в python 3 и unicode type в python 2)

...