1396 votes

Meilleur moyen de convertir une chaîne en octets en Python 3 ?

TypeError : 'str' ne prend pas en charge l'interface tampon propose deux méthodes possibles pour convertir une chaîne de caractères en octets :

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

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

Quelle méthode est la plus pythique ?

76 votes

Utiliser encode/décode est plus courant, et peut-être plus clair.

30 votes

@LennartRegebro Je rejette. Même si c'est plus commun, en lisant "bytes()" je sais ce qu'il fait, alors que encode() ne me donne pas l'impression de coder en octets.

5 votes

Ce qui est une bonne raison de l'utiliser jusqu'à ce qu'il soit fait vous vous sentez comme ça, alors vous êtes un pas de plus vers le zen d'Unicode.

830voto

agf Points 45052

Si vous regardez les documents pour bytes il vous dirige vers bytearray :

bytearray([source[, encodage[, erreurs]]])

Retourne un nouveau tableau d'octets. Le type bytearray est une séquence mutable d'entiers dans l'intervalle 0 <= x < 256. Il dispose de la plupart des méthodes habituelles des séquences mutables, décrites dans Types de séquences mutables, ainsi que de la plupart des méthodes dont dispose le type bytes, voir Méthodes des octets et des tableaux d'octets.

Le paramètre source facultatif peut être utilisé pour initialiser le tableau de plusieurs manières différentes :

S'il s'agit d'une chaîne de caractères, vous devez également fournir les paramètres d'encodage (et éventuellement, les erreurs) ; bytearray() convertit alors la chaîne en octets en utilisant str.encode().

Si c'est un entier, le tableau aura cette taille et sera initialisé avec des octets nuls.

S'il s'agit d'un objet conforme à l'interface de tampon, un tampon en lecture seule de l'objet sera utilisé pour initialiser le tableau d'octets.

Si c'est un itérable, ce doit être un itérable d'entiers dans l'intervalle 0 <= x < 256, qui sont utilisés comme contenu initial du tableau.

Sans argument, un tableau de taille 0 est créé.

Alors bytes peut faire beaucoup plus que simplement encoder une chaîne. C'est pythique qu'il vous permette d'appeler le constructeur avec tout type de paramètre source qui a du sens.

Pour coder une chaîne de caractères, je pense que some_string.encode(encoding) est plus pythique que l'utilisation du constructeur, parce qu'elle est la plus auto-documentée -- "prendre cette chaîne et l'encoder avec cet encodage" est plus clair que bytes(some_string, encoding) -- il n'y a pas de verbe explicite lorsque vous utilisez le constructeur.

J'ai vérifié la source Python. Si vous passez une chaîne unicode à bytes en utilisant CPython, il appelle PyUnicode_AsEncodedStringing qui est l'implémentation de encode donc vous ne faites que sauter un niveau d'indirection si vous appelez encode vous-même.

Voir aussi le commentaire de Serdalis -- unicode_string.encode(encoding) est également plus pythonique car son inverse est byte_string.decode(encoding) et la symétrie est agréable.

123 votes

+1 pour avoir un bon argument et des citations de la docs python. Aussi unicode_string.encode(encoding) s'accorde bien avec bytearray.decode(encoding) quand tu voudras récupérer ta ficelle.

12 votes

bytearray est utilisé lorsque vous avez besoin d'un objet mutable. Vous n'en avez pas besoin pour de simples str``bytes les conversions.

9 votes

@EugeneHomyakov Cela n'a rien à voir avec bytearray sauf que les docs pour bytes ne donnent pas de détails, ils disent juste "ceci est une version immuable de bytearray ", donc je dois citer à partir de là.

654voto

hasanatkazmi Points 395

C'est plus facile qu'on ne le croit :

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

75 votes

Il sait comment faire, il demande juste quel est le meilleur moyen. Relisez la question, s'il vous plaît.

34 votes

FYI : str.decode(bytes) n'a pas fonctionné pour moi (Python 3.3.3 a dit "type object 'str' has no attribute 'decode'") J'ai utilisé bytes.decode() à la place.

7 votes

@Mike : utiliser obj.method() au lieu de la syntaxe cls.method(obj) syntaxe, c'est-à-dire utiliser bytestring = unicode_text.encode(encoding) y unicode_text = bytestring.decode(encoding) .

264voto

Antti Haapala Points 11542

El absolument Le meilleur moyen n'est ni l'un ni l'autre, mais le troisième. Le premier paramètre à encode La valeur par défaut est 'utf-8' depuis Python 3.0. Le meilleur moyen est donc

b = mystring.encode()

Cela sera également plus rapide, car l'argument par défaut ne résulte pas dans la chaîne de caractères "utf-8" dans le code C, mais NULL qui est beaucoup plus rapide à vérifier !

Voici quelques horaires :

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

Malgré cet avertissement, les temps sont restés très stables après plusieurs passages - l'écart n'était que de ~2 %.


Utilisation de encode() sans argument n'est pas compatible avec Python 2, car dans Python 2 le codage des caractères par défaut est 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)

62voto

Brent Points 33

Réponse à un problème légèrement différent :

Vous avez une séquence d'unicode brut qui a été enregistrée dans une variable str :

s_str: str = "\x00\x01\x00\xc0\x01\x00\x00\x00\x04"

Vous devez être capable d'obtenir l'octet littéral de cet unicode (pour struct.unpack(), etc.)

s_bytes: bytes = b'\x00\x01\x00\xc0\x01\x00\x00\x00\x04'

Solution :

s_new: bytes = bytes(s, encoding="raw_unicode_escape")

Référence (faites défiler vers le haut pour les encodages standard) :

Encodages spécifiques à Python

2voto

Jason Morgan Points 864

Que pensez-vous de Python 3 ' vue de la mémoire ' manière.

Memoryview est une sorte de mélange des modules byte/bytearray et struct, avec plusieurs avantages.

  • Ne se limite pas aux textes et aux octets, traite également les mots de 16 et 32 bits.
  • Faire face à l'endiannité
  • Fournit une interface à très faible coût pour les fonctions et les données C/C++ liées.

Exemple le plus simple, pour un tableau d'octets :

memoryview(b"some bytes").tolist()

[115, 111, 109, 101, 32, 98, 121, 116, 101, 115]

Ou pour une chaîne unicode, (qui est convertie en tableau d'octets)

memoryview(bytes("\u0075\u006e\u0069\u0063\u006f\u0064\u0065\u0020", "UTF-16")).tolist()

[255, 254, 117, 0, 110, 0, 105, 0, 99, 0, 111, 0, 100, 0, 101, 0, 32, 0]

#Another way to do the same
memoryview("\u0075\u006e\u0069\u0063\u006f\u0064\u0065\u0020".encode("UTF-16")).tolist()

[255, 254, 117, 0, 110, 0, 105, 0, 99, 0, 111, 0, 100, 0, 101, 0, 32, 0]

Peut-être avez-vous besoin de mots plutôt que d'octets ?

memoryview(bytes("\u0075\u006e\u0069\u0063\u006f\u0064\u0065\u0020", "UTF-16")).cast("H").tolist()

[65279, 117, 110, 105, 99, 111, 100, 101, 32]

memoryview(b"some  more  data").cast("L").tolist()

[1701670771, 1869422624, 538994034, 1635017060]

Un mot d'avertissement. Faites attention aux interprétations multiples de l'ordre des octets avec des données de plus d'un octet :

txt = "\u0075\u006e\u0069\u0063\u006f\u0064\u0065\u0020"
for order in ("", "BE", "LE"):
    mv = memoryview(bytes(txt, f"UTF-16{order}"))
    print(mv.cast("H").tolist())

[65279, 117, 110, 105, 99, 111, 100, 101, 32]
[29952, 28160, 26880, 25344, 28416, 25600, 25856, 8192]
[117, 110, 105, 99, 111, 100, 101, 32]

Je ne sais pas si c'est intentionnel ou s'il s'agit d'un bug, mais j'ai été surpris !

L'exemple a utilisé UTF-16, pour une liste complète des codecs voir Registre des codecs en Python 3.10

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X