Il modo migliore per convertire string in byte in Python 3?


861

Sembra che ci siano due modi diversi per convertire una stringa in byte, come si vede nelle risposte a TypeError: 'str' non supporta l'interfaccia buffer

Quale di questi metodi sarebbe migliore o più Pythonic? O è solo una questione di preferenze personali?

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

b = mystring.encode('utf-8')

42
L'uso della codifica / decodifica è più comune e forse più chiaro.
Lennart Regebro,

11
@LennartRegebro respingo. Anche se è più comune, leggendo "bytes ()" so cosa sta facendo, mentre encode () non mi fa sentire che sta codificando in byte.
m3nda,

2
@ erm3nda Che è una buona ragione per usarlo fino a quando non ti sembra così, allora sei un passo avanti verso Unicode Zen.
Lennart Regebro,

4
@LennartRegebro Mi sento abbastanza bene da usare bytes(item, "utf8"), dato che esplicito è meglio che implicito, quindi ... per str.encode( )impostazione predefinita, i byte diventano silenziosamente byte, rendendoti più Unicode-zen ma meno Explicit-Zen. Anche "comune" non è un termine che mi piace seguire. Inoltre, bytes(item, "utf8")è più simile a str(), e alle b"string"notazioni. Mi scuso se sono così indifferente per capire le tue ragioni. Grazie.
m3nda,

4
@ erm3nda se leggi la risposta accettata puoi vedere che encode()non chiama bytes(), è il contrario. Ovviamente non è immediatamente ovvio ed è per questo che ho posto la domanda.
Mark Ransom,

Risposte:


571

Se guardi i documenti per bytes, ti indicano bytearray:

bytearray ([fonte [, codifica [, errori]]])

Restituisce un nuovo array di byte. Il tipo bytearray è una sequenza mutabile di numeri interi nell'intervallo 0 <= x <256. Ha la maggior parte dei metodi usuali di sequenze mutabili, descritti in Tipi di sequenza mutabili, così come la maggior parte dei metodi che ha il tipo di byte, vedi Byte e Metodi di array di byte.

Il parametro sorgente opzionale può essere utilizzato per inizializzare l'array in diversi modi:

Se è una stringa, è necessario fornire anche i parametri di codifica (e, facoltativamente, errori); bytearray () quindi converte la stringa in byte usando str.encode ().

Se è un numero intero, l'array avrà quella dimensione e verrà inizializzato con byte null.

Se si tratta di un oggetto conforme all'interfaccia buffer, verrà utilizzato un buffer di sola lettura dell'oggetto per inizializzare l'array di byte.

Se è un iterabile, deve essere un iterabile di numeri interi nell'intervallo 0 <= x <256, che vengono utilizzati come contenuto iniziale dell'array.

Senza un argomento, viene creato un array di dimensioni 0.

Quindi bytespuò fare molto di più che semplicemente codificare una stringa. È Pythonic che ti permetterebbe di chiamare il costruttore con qualsiasi tipo di parametro sorgente che abbia senso.

Per codificare una stringa, penso che some_string.encode(encoding)sia più Pythonic che usare il costruttore, perché è il più autocompassante - "prendere questa stringa e codificarla con questa codifica" è più chiaro di bytes(some_string, encoding)- non c'è un verbo esplicito quando si usa il costruttore.

Modifica: ho controllato la fonte Python. Se si passa una stringa unicode bytesall'utilizzo di CPython, chiama PyUnicode_AsEncodedString , che è l'implementazione di encode; quindi stai solo saltando un livello di riferimento indiretto se ti chiami encode.

Inoltre, vedi il commento di Serdalis - unicode_string.encode(encoding)è anche più pitone perché è inverso byte_string.decode(encoding)e la simmetria è piacevole.


73
+1 per avere un buon argomento e citazioni dai documenti di Python. Si unicode_string.encode(encoding)abbina bene anche bytearray.decode(encoding)quando vuoi riavere la tua corda.
Serdalis,

6
bytearrayviene utilizzato quando è necessario un oggetto mutabile. Non è necessario per conversioni str↔ semplici bytes.
hamstergene,

8
@EugeneHomyakov Questo non ha nulla a che fare con l' bytearrayeccezione del fatto che i documenti per bytesnon fornire dettagli, dicono solo "questa è una versione immutabile di bytearray" quindi devo citare da lì.
AGF

1
Solo una nota di cautela da Python in a Nutshell su bytes: Evitare di utilizzare il tipo di byte in funzione con un argomento intero. In v2 questo restituisce il numero intero convertito in una stringa (byte) perché byte è un alias per str, mentre in v3 restituisce un bytestring contenente il numero dato di caratteri null. Quindi, ad esempio, anziché i byte di espressione v3 (6), usa l'equivalente b '\ x00' * 6, che funziona perfettamente allo stesso modo in ogni versione.
holdenweb,

2
Solo una nota, che se stai provando a convertire i dati binari in una stringa, molto probabilmente dovrai usare qualcosa di simile byte_string.decode('latin-1')poiché utf-8non copre l'intero intervallo da 0x00 a 0xFF (0-255), controlla i documenti di Python per Ulteriori informazioni.
iggy12345,

349

È più facile di quanto si pensi:

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

37
Sa come farlo, sta solo chiedendo quale sia il modo migliore. Rileggi la domanda.
AGF

30
Cordiali saluti: str.decode (byte) non ha funzionato per me (Python 3.3.3 ha detto che "type object 'str' non ha attributo 'decode'") Ho usato invece bytes.decode ()
Mike

6
@Mike: usa la obj.method()sintassi invece della cls.method(obj)sintassi, cioè usa bytestring = unicode_text.encode(encoding)e unicode_text = bytestring.decode(encoding).
jfs,

2
... cioè stai inutilmente facendo un metodo illimitato, e poi chiamandolo passando selfcome primo argomento
Antti Haapala

2
@KolobCanyon La domanda mostra già il modo giusto per farlo: chiama encodecome metodo associato sulla stringa. Questa risposta suggerisce che dovresti invece chiamare il metodo non associato e passargli la stringa. Questa è l'unica nuova informazione nella risposta, ed è sbagliata.
abarnert,

144

Il modo assolutamente migliore non è nessuno dei 2, ma il 3 °. Il primo parametro predefinito da Python 3.0. Quindi il modo migliore èencode 'utf-8'

b = mystring.encode()

Questo sarà anche più veloce, perché l'argomento predefinito non risulta nella stringa "utf-8"nel codice C, ma NULL, che è molto più veloce da controllare!

Ecco alcuni tempi:

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

Nonostante l'avvertimento, i tempi erano molto stabili dopo ripetute corse - la deviazione era solo del 2% circa.


L'uso encode()senza argomento non è compatibile con Python 2, poiché in Python 2 la codifica dei caratteri predefinita è 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)

2
C'è solo una differenza considerevole qui perché (a) la stringa è ASCII pura, il che significa che la memoria interna è già la versione UTF-8, quindi cercare il codec è quasi l'unico costo coinvolto, e (b) la stringa è minuscola , quindi anche se dovessi codificare, non farebbe molta differenza. Provalo con, diciamo, '\u00012345'*10000. Entrambi prendono 28,8us sul mio laptop; i 50 ns extra sono presumibilmente persi nell'errore di arrotondamento. Naturalmente questo è un esempio piuttosto estremo, ma 'abc'è altrettanto estremo nella direzione opposta.
abarnert,

@abarnert true, ma anche in questo caso, non vi è alcun motivo per passare l'argomento come stringa.
Antti Haapala,

Secondo questo, gli argomenti predefiniti sono sempre "assolutamente il modo migliore" per fare le cose, giusto? Questo tipo di analisi della velocità sembrerebbe una probabile esagerazione se si trattasse di discutere del codice C. In un linguaggio interpretato, mi lascia senza parole.
hmijail piange le dimissioni il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.