Байты против 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).