Байты против bytearray в Python 2.6 и 3

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

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

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

дает:

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

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

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

дает:

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

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

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

Ответы

Ответ 1

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

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

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

Ответ 2

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

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

Ответ 3

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

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

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

дает:

<class 'int'>
<class 'int'>
Итератор

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

Ответ 4

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

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

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

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

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

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

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

Ответ 5

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 типом в python 3 и unicode типом в python 2).