По-видимому, существует два различных способа преобразования строки в байты, как видно из ответов на сайте https://stackoverflow.com/questions/5471158/typeerror-str-does-not-support-the-buffer-interface.
Какой из этих способов будет лучше или более Pythonic? Или это просто вопрос личных предпочтений?
b = bytes(mystring, 'utf-8')
b = mystring.encode('utf-8')
Если посмотреть документацию по bytes
, то она указывает на bytearray
:
bytearray([source[, encoding[, errors]])
Возвращает новый массив байтов. Тип bytearray представляет собой изменяемую последовательность целых чисел в диапазоне 0<= x<256. Он имеет большинство обычных методов мутабельных последовательностей, описанных в разделе Мутабельные типы последовательностей, а также большинство методов, которыми обладает тип bytes, см. раздел Методы байтов и байтовых массивов.
Необязательный параметр source может быть использован для инициализации массива несколькими различными способами:
Если это строка, то необходимо также указать параметры кодировки (и, опционально, ошибки); тогда bytearray() преобразует строку в байты с помощью str.encode()..
Если это целое число, то массив будет иметь этот размер и инициализируется нулевыми байтами..
Если это итерируемый массив, то он должен быть итерируемым массивом целых чисел в диапазоне 0 <= x <256, которые используются в качестве начального содержимого массива. >__Если это объект, соответствующий интерфейсу буфера, то для инициализации массива байт будет использоваться буфер чтения объекта.
Без аргумента создается массив размера 0..
Таким образом, bytes
может делать гораздо больше, чем просто кодировать строку. По Питону, это позволяет вызывать конструктор с любым типом исходного параметра, который имеет смысл.
Для кодирования строки я считаю, что some_string.encode(encoding)
более питоничен, чем использование конструктора, поскольку он наиболее самодокументирован - "взять эту строку и закодировать ее в этой кодировке" понятнее, чем bytes(some_string, encoding)
- при использовании конструктора нет явного глагола.
Правка: Я проверил исходный текст на Python. Если передать строку в юникоде в bytes
с помощью CPython, то вызывается PyUnicode_AsEncodedString, который является реализацией encode
; так что вы просто пропускаете уровень косвенности, если вызываете encode
самостоятельно.
Кроме того, см. комментарий Serdalis' -- unicode_string.encode(encoding)
также более питоничен, поскольку его обратным показателем является byte_string.decode(encoding)
, а симметрия - это хорошо.
Это проще, чем кажется:
my_str = "hello world"
my_str_as_bytes = str.encode(my_str)
type(my_str_as_bytes) # ensure it is byte representation
my_decoded_str = my_str_as_bytes.decode()
type(my_decoded_str) # ensure it is string representation
Абсолютно лучшим способом является ни один из двух, а третий. Начиная с версии Python 3.0 первый параметр encode
по умолчанию* принимает значение 'utf-8'
. Таким образом, наилучшим вариантом является
b = mystring.encode()
Это также будет быстрее, так как аргумент по умолчанию приводит в коде на Си не к строке "utf-8"
, а к NULL
, что гораздо быстрее проверить!
Вот некоторые тайминги:
In [1]: %timeit -r 10 'abc'.encode('utf-8')
The slowest run took 38.07 times longer than the fastest.
This could mean that an intermediate result is being cached.
10000000 loops, best of 10: 183 ns per loop
In [2]: %timeit -r 10 'abc'.encode()
The slowest run took 27.34 times longer than the fastest.
This could mean that an intermediate result is being cached.
10000000 loops, best of 10: 137 ns per loop
Несмотря на предупреждение, времена оказались очень стабильными после многократных запусков - отклонение составило всего ~2%.
Использование encode()
без аргумента несовместимо с Python 2, поскольку в Python 2 кодировка символов по умолчанию ASCII.
>>> 'äöä'.encode()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)