Der beste Weg, um String in Python 3 in Bytes zu konvertieren?

860

Wie aus den Antworten auf TypeError hervorgeht, gibt es zwei verschiedene Möglichkeiten, eine Zeichenfolge in Bytes zu konvertieren: 'str' unterstützt die Pufferschnittstelle nicht

Welche dieser Methoden wäre besser oder pythonischer? Oder ist es nur eine Frage der persönlichen Präferenz?

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

b = mystring.encode('utf-8')
Mark Ransom
quelle
42
Die Verwendung von Codierung / Decodierung ist häufiger und möglicherweise klarer.
Lennart Regebro
11
@ LennartRegebro entlasse ich. Selbst wenn es üblicher ist, "bytes ()" zu lesen, weiß ich, was es tut, während encode () mir nicht das Gefühl gibt, dass es in Bytes codiert.
m3nda
2
@ erm3nda Was ein guter Grund ist, es zu verwenden, bis es sich so anfühlt, dann sind Sie Unicode Zen einen Schritt näher.
Lennart Regebro
3
@LennartRegebro Ich fühle mich gut genug, um es nur zu verwenden bytes(item, "utf8"), da explizit besser als implizit ist, also ... str.encode( )standardmäßig lautlos Bytes verwendet werden, wodurch Sie mehr Unicode-Zen, aber weniger explizites Zen erhalten. Auch "common" ist kein Begriff, dem ich gerne folge. Auch bytes(item, "utf8")ist eher wie die str()und b"string"Notationen. Ich entschuldige mich, wenn ich nicht in der Lage bin, Ihre Gründe zu verstehen. Vielen Dank.
m3nda
4
@ erm3nda Wenn Sie die akzeptierte Antwort lesen, können Sie sehen, dass encode()sie nicht anruft bytes(), sondern umgekehrt. Das ist natürlich nicht sofort klar, weshalb ich die Frage gestellt habe.
Mark Ransom

Antworten:

571

Wenn man sich die Dokumente sucht bytes, es verweist Sie auf bytearray:

Bytearray ([Quelle [, Codierung [, Fehler]]])

Gibt ein neues Array von Bytes zurück. Der Bytearray-Typ ist eine veränderbare Folge von ganzen Zahlen im Bereich von 0 <= x <256. Er enthält die meisten der üblichen Methoden für veränderliche Sequenzen, die unter Mutable Sequence Types beschrieben sind, sowie die meisten Methoden, die der Byte-Typ hat, siehe Bytes und Byte-Array-Methoden.

Der optionale Quellparameter kann verwendet werden, um das Array auf verschiedene Arten zu initialisieren:

Wenn es sich um eine Zeichenfolge handelt, müssen Sie auch die Codierungsparameter (und optional Fehler) angeben. bytearray () konvertiert dann den String mit str.encode () in Bytes.

Wenn es sich um eine Ganzzahl handelt, hat das Array diese Größe und wird mit Null-Bytes initialisiert.

Wenn es sich um ein Objekt handelt, das der Pufferschnittstelle entspricht, wird ein schreibgeschützter Puffer des Objekts verwendet, um das Byte-Array zu initialisieren.

Wenn es sich um eine Iterable handelt, muss es sich um eine Iterable von Ganzzahlen im Bereich 0 <= x <256 handeln, die als Anfangsinhalt des Arrays verwendet werden.

Ohne Argument wird ein Array der Größe 0 erstellt.

So byteskann viel mehr als nur einen String kodieren. Es ist pythonisch, dass Sie den Konstruktor mit jedem sinnvollen Quellparameter aufrufen können.

Für die Codierung einer Zeichenfolge denke ich, dass dies some_string.encode(encoding)pythonischer ist als die Verwendung des Konstruktors, da es am selbstdokumentierendsten ist - "Nehmen Sie diese Zeichenfolge und codieren Sie sie mit dieser Codierung" ist klarer als bytes(some_string, encoding)- es gibt kein explizites Verb, wenn Sie das verwenden Konstrukteur.

Bearbeiten: Ich habe die Python-Quelle überprüft. Wenn Sie eine Unicode-Zeichenfolge an bytesCPython übergeben, wird PyUnicode_AsEncodedString aufgerufen. Dies ist die Implementierung von encode; Sie überspringen also nur eine Indirektionsebene, wenn Sie sich encodeselbst anrufen .

Siehe auch Serdalis 'Kommentar - unicode_string.encode(encoding)ist auch pythonischer, weil seine Umkehrung byte_string.decode(encoding)und Symmetrie schön ist.

agf
quelle
73
+1 für ein gutes Argument und Zitate aus den Python-Dokumenten. Auch unicode_string.encode(encoding)paßt gut , bytearray.decode(encoding)wenn Sie Ihren String zurück wollen.
Serdalis
6
bytearraywird verwendet, wenn Sie ein veränderbares Objekt benötigen. Sie brauchen es nicht für einfache strbytesKonvertierungen.
Hamstergen
8
@EugeneHomyakov Das hat nichts damit zu tun, bytearrayaußer dass die Dokumente für byteskeine Details angeben, sie sagen nur "dies ist eine unveränderliche Version von bytearray", also muss ich von dort aus zitieren.
Agf
1
Nur ein Warnruf aus Python in a Nutshell über bytes: Vermeiden Sie den Bytes Typ als Funktion mit einem ganzzahligen Argumente. In Version 2 wird die in eine (Byte-) Zeichenfolge konvertierte Ganzzahl zurückgegeben, da Bytes ein Alias ​​für str ist, während in Version 3 ein Bytestring zurückgegeben wird, der die angegebene Anzahl von Nullzeichen enthält. Verwenden Sie beispielsweise anstelle der v3-Ausdrucksbytes (6) das entsprechende b '\ x00' * 6, das in jeder Version nahtlos auf die gleiche Weise funktioniert.
Holdenweb
2
Nur ein Hinweis, dass , wenn Sie versuchen , binäre Daten in eine Zeichenfolge zu konvertieren, werden Sie wahrscheinlich verwenden müssen , um so etwas wie byte_string.decode('latin-1')als utf-8nicht den gesamten Bereich 0x00 bis 0xFF (0-255) decken, die Python - Check - out - Dokumente für Mehr Info.
iggy12345
348

Es ist einfacher als gedacht:

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
hasanatkazmi
quelle
37
Er weiß, wie es geht, er fragt nur, welcher Weg besser ist. Bitte lesen Sie die Frage erneut.
Agf
30
Zu Ihrer Information: str.decode (Bytes) hat bei mir nicht funktioniert (Python 3.3.3 sagte "Typobjekt 'str' hat kein Attribut 'decode'"). Ich habe stattdessen bytes.decode () verwendet
Mike
6
@Mike: Verwenden Sie obj.method()Syntax anstelle von cls.method(obj)Syntax, dh verwenden Sie bytestring = unicode_text.encode(encoding)und unicode_text = bytestring.decode(encoding).
JFS
2
... dh Sie machen unnötig eine ungebundene Methode und nennen sie dann selfals erstes Argument
Antti Haapala
2
@KolobCanyon Die Frage zeigt bereits den richtigen Weg - Aufruf encodeals gebundene Methode für die Zeichenfolge. Diese Antwort schlägt vor, dass Sie stattdessen die ungebundene Methode aufrufen und die Zeichenfolge übergeben sollten. Das ist die einzige neue Information in der Antwort, und sie ist falsch.
abarnert
144

Der absolut beste Weg ist keiner der 2, sondern der 3 .. Der erste Standardparameter seit Python 3.0. Somit ist der beste Wegencode 'utf-8'

b = mystring.encode()

Dies wird auch schneller, da das Standard - Argument nicht im String führt "utf-8"im C - Code, aber NULL, das ist viel schneller zu überprüfen!

Hier einige Timings:

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

Trotz der Warnung waren die Zeiten nach wiederholten Läufen sehr stabil - die Abweichung betrug nur ~ 2 Prozent.


Die Verwendung encode()ohne Argument ist nicht Python 2-kompatibel, da in Python 2 die Standardzeichenkodierung ASCII ist .

>>> 'äöä'.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)
Antti Haapala
quelle
2
Hier gibt es nur einen beträchtlichen Unterschied, da (a) die Zeichenfolge reines ASCII ist, was bedeutet, dass der interne Speicher bereits die UTF-8-Version ist, sodass das Nachschlagen des Codecs fast die einzigen Kosten sind und (b) die Zeichenfolge winzig ist Selbst wenn Sie codieren müssten, würde dies keinen großen Unterschied machen. Versuchen Sie es mit, sagen wir '\u00012345'*10000. Beide nehmen 28.8us auf meinem Laptop; Die zusätzlichen 50 ns gehen vermutlich im Rundungsfehler verloren. Natürlich ist dies ein ziemlich extremes Beispiel - aber es 'abc'ist genauso extrem in die entgegengesetzte Richtung.
abarnert
@abarnert true, aber selbst dann gibt es keinen Grund, das Argument als Zeichenfolge zu übergeben.
Antti Haapala
Demnach sind die Standardargumente immer "absolut der beste Weg", Dinge zu tun, oder? Diese Art der Geschwindigkeitsanalyse würde sich wie eine wahrscheinliche Übertreibung anfühlen, wenn es um die Erörterung von C-Code geht. In einer interpretierten Sprache macht es mich sprachlos.
hmijail trauert um den 14.