Beste måten å konvertere streng til byte i Python 3?

Det ser ut til å være to forskjellige måter å konvertere en streng til byte på, som vist i svarene på https://stackoverflow.com/questions/5471158/typeerror-str-does-not-support-the-buffer-interface.

Hvilken av disse metodene ville være bedre eller mer Pythonic? Eller er det bare et spørsmål om personlig preferanse?

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

b = mystring.encode('utf-8')
Løsning

Hvis du ser på dokumentasjonen for bytes, peker den til bytearray:

bytearray([source[, encoding[, errors]]]))

Returnerer en ny bytearray. Bytearray-typen er en foranderlig sekvens av heltall i området 0 <= x < 256. Den har de fleste av de vanlige metodene for mutable sekvenser, beskrevet i Mutable Sequence Types, samt de fleste metodene som byte-typen har, se Bytes og Byte Array Methods.

Den valgfrie kildeparameteren kan brukes til å initialisere arrayet på noen få forskjellige måter:

Hvis det er en streng, må du også gi koding (og eventuelt feil) parametere; bytearray() konverterer deretter strengen til byte ved hjelp av str.encode()..

Hvis det er et heltall, vil arrayet ha den størrelsen og vil bli initialisert med null byte..

Hvis det er et objekt som samsvarer med buffergrensesnittet, vil en skrivebeskyttet buffer av objektet bli brukt til å initialisere bytearrayet.

Hvis det er en iterabel, må det være en iterabel av heltall i området 0 Uten et argument opprettes en matrise med størrelse 0.__

bytes kan gjøre mye mer enn bare å kode en streng. Det er Pythonic at det vil tillate deg å ringe konstruktøren med hvilken som helst type kildeparameter som gir mening.

For koding av en streng tror jeg at some_string.encode(encoding) er mer Pythonic enn å bruke konstruktøren, fordi det er den mest selvdokumenterende - "ta denne strengen og kod den med denne kodingen" er tydeligere enn bytes(some_string, encoding) - det er ikke noe eksplisitt verb når du bruker konstruktøren.

Edit: Jeg sjekket Python-kilden. Hvis du sender en unicode-streng til bytes ved hjelp av CPython, kaller den PyUnicode_AsEncodedString, som er implementeringen av encode; så du hopper bare over et nivå av indirekte hvis du kaller encode selv.

Se også Serdalis' kommentar -- unicode_string.encode(encoding) er også mer Pythonic fordi dens inverse er byte_string.decode(encoding) og symmetri er fint.

Kommentarer (5)

Det er enklere enn man tror:

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
Kommentarer (10)

Den absolutt beste måten er ingen av de 2, men den 3. Den første parameteren til encode default to 'utf-8' helt siden Python 3.0. Den beste måten er derfor

b = mystring.encode()

Dette vil også være raskere, fordi standardargumentet ikke resulterer i strengen "utf-8" i C-koden, men NULL, som er mye raskere å sjekke!

Her er noen tidsangivelser:

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

Til tross for advarselen var tidene veldig stabile etter gjentatte kjøringer - avviket var bare ~ 2 prosent.


Bruk av encode() uten et argument er ikke Python 2-kompatibelt, ettersom standard tegnkoding i Python 2 er 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)
Kommentarer (2)