A melhor maneira de converter cordas em bytes em Python 3?

Parece haver duas formas diferentes de converter uma corda em bytes, como se vê nas respostas a https://stackoverflow.com/questions/5471158/typeerror-str-does-not-support-the-buffer-interface

Qual destes métodos seria melhor ou mais pítonico? Ou é apenas uma questão de preferência pessoal?

b = bytes(mystring, 'utf-8')

b = mystring.encode('utf-8')
Solução

Se você olhar os documentos para "bytes", ele aponta para bytearray:

bytearray([fonte[, codificação[, erros]]])

Devolva um novo conjunto de bytes. O tipo de bytearray é uma sequência mutável de números inteiros no intervalo 0 <= x < 256. Tem a maioria dos métodos usuais de sequências mutáveis, descritos em Tipos de Sequência Muda, assim como a maioria dos métodos que o tipo de bytes tem, veja Métodos de Bytes e Byte Array.

O parâmetro opcional da fonte pode ser usado para inicializar o array de algumas maneiras diferentes:

Se for uma string, você também deve dar os parâmetros de codificação (e opcionalmente, erros); bytearray() então converte a string em bytes usando str.encode().

Se for um número inteiro, o array terá esse tamanho e será inicializado com bytes nulos.

Se for um objeto em conformidade com a interface buffer, um buffer só de leitura do objeto será usado para inicializar a matriz de bytes.

Se for um iterável, deve ser um iterável de inteiros no intervalo 0 Sem discussão, é criado um array de tamanho 0.__

Então "bytes" pode fazer muito mais do que codificar uma string. It's Pythonic que permite que você chame o construtor com qualquer tipo de parâmetro de fonte que faça sentido.

Para codificar uma string, eu acho que some_string.encode(encoding) é mais Pythonic do que utilizar o construtor, porque ele é o mais auto documentado -- "pegue esta string e codifique-a com esta codificação" é mais claro que bytes(some_string, encoding) -- não há verbo explícito quando você utiliza o construtor.

Edit: Eu verifiquei a fonte Python. Se você passar uma string unicode para bytes utilizando CPython, ela chama PyUnicode_AsEncodedString, que é a implementação do encode; então você'está apenas pulando um nível de indireção se você mesmo chamar o encode.

Também, veja Serdalis' comente -- unicode_string.encode(encoding) também é mais Pythonic porque seu inverso é byte_string.decode(encoding) e a simetria é agradável.

Comentários (5)

It's mais fácil do que se pensa:

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
Comentários (10)

O absolutamente melhor caminho não é nenhum dos dois, mas o terceiro. O primeiro parâmetro para encode defaults to 'utf-8' desde Python 3.0. Assim, a melhor maneira é

b = mystring.encode()

Isso também será mais rápido, porque o argumento padrão não resulta na string "utf-8" no código C, mas NULL, que é muito mais rápido para verificar!

Aqui estão alguns horários:

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

Apesar do aviso, os tempos foram muito estáveis após repetidas corridas - o desvio foi de apenas ~2 por cento.


Utilizando encode() sem um argumento não é compatível com Python 2, pois em Python 2 a codificação de caracteres padrão é ASCII.

>>> 'äöä'.encode()
Traceback (most recent call last):
  File "", line 1, in 
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)
Comentários (2)