Parece que hay dos formas diferentes de convertir una cadena en bytes, como se ve en las respuestas a https://stackoverflow.com/questions/5471158/typeerror-str-does-not-support-the-buffer-interface
¿Cuál de estos métodos sería mejor o más pitónico? ¿O es sólo una cuestión de preferencia personal?
b = bytes(mystring, 'utf-8')
b = mystring.encode('utf-8')
Si miras la documentación de bytes
, te indica bytearray
:
bytearray([fuente[, codificación[, errores]])
Devuelve un nuevo array de bytes. El tipo bytearray es una secuencia mutable de enteros en el rango 0 <= x < 256. Tiene la mayoría de los métodos habituales de las secuencias mutables, descritos en Tipos de Secuencias Mutables, así como la mayoría de los métodos que tiene el tipo bytes, ver Métodos de Bytes y Matrices de Bytes.
El parámetro opcional source puede ser usado para inicializar el array de varias maneras:
Si es una cadena, también debe dar los parámetros de codificación (y opcionalmente, errores); bytearray() entonces convierte la cadena a bytes usando str.encode().
Si es un entero, el array tendrá ese tamaño y se inicializará con bytes nulos.__
Si se trata de un objeto que se ajusta a la interfaz del buffer, se utilizará un buffer de sólo lectura del objeto para inicializar el array de bytes.__
Si es un iterable, debe ser un iterable de enteros en el rango 0 <= x < 256, que se utilizan como contenido inicial del array.__
Sin argumento, se crea un array de tamaño 0.
Así que bytes
puede hacer mucho más que codificar una cadena. Es Pythonic que te permitiría llamar al constructor con cualquier tipo de parámetro fuente que tenga sentido.
Para codificar una cadena, creo que alguna_cadena.codificar(codificación)
es más pitónico que usar el constructor, porque es el más autodocumentado -- "tomar esta cadena y codificarla con esta codificación" es más claro que bytes(alguna_cadena, codificación)
-- no hay un verbo explícito cuando se usa el constructor.
Edición: He comprobado el código fuente de Python. Si pasas una cadena unicode a bytes
usando CPython, llama a PyUnicode_AsEncodedString, que es la implementación de encode
; así que sólo estás saltando un nivel de indirección si llamas a encode
tú mismo.
Además, vea el comentario de Serdalis' unicode_string.encode(encoding)
también es más pitónico porque su inverso es byte_string.decode(encoding)
y la simetría es agradable.
Es más fácil de lo que se cree:
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
La forma absolutamente mejor no es ninguna de las dos, sino la tercera. El primer parámetro de encode
por defecto 'utf-8'
desde Python 3.0. Por lo tanto, la mejor manera es
b = mystring.encode()
Esto también será más rápido, porque el argumento por defecto no resulta en la cadena "utf-8"en el código C, sino *
NULL`, ¡que es mucho* más rápido de comprobar!
Aquí hay algunos tiempos:
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
A pesar de la advertencia, los tiempos fueron muy estables después de repetidas ejecuciones - la desviación fue de sólo ~ 2 por ciento.
Usar encode()
sin un argumento no es compatible con Python 2, ya que en Python 2 la codificación de caracteres por defecto es 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)