web-dev-qa-db-fra.com

Meilleure façon de convertir une chaîne en octets dans Python 3?

Il semble y avoir deux manières différentes de convertir une chaîne en octets, comme indiqué dans les réponses à TypeError: 'str' ne prend pas en charge l'interface de mémoire tampon

Laquelle de ces méthodes serait meilleure ou plus pythonique? Ou est-ce juste une question de préférence personnelle?

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

b = mystring.encode('utf-8')
659
Mark Ransom

Si vous regardez la documentation pour bytes, elle vous indique bytearray :

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

Renvoie un nouveau tableau d'octets. Le type bytearray est une séquence mutable d'entiers comprise dans la plage 0 <= x <256. Il contient la plupart des méthodes habituelles de séquences mutables, décrites dans Types de séquence mutables, ainsi que la plupart des méthodes associées au type d'octets, voir Octets et Méthodes de tableau d'octets.

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

S'il s'agit d'une chaîne, vous devez également donner les paramètres d'encodage (et éventuellement d'erreurs); bytearray () convertit ensuite la chaîne en octets à l'aide de str.encode ().

S'il s'agit d'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.

S'il s'agit d'un élément itérable, il doit s'agir d'un nombre itérable compris dans l'intervalle 0 <= x <256, qui sont utilisés comme contenu initial du tableau.

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

Ainsi, bytes peut faire beaucoup plus que simplement encoder une chaîne. C'est Pythonic que cela vous permettrait d'appeler le constructeur avec n'importe quel type de paramètre source qui ait du sens.

Pour encoder une chaîne, je pense que some_string.encode(encoding) est plus Pythonic que le constructeur, car c'est le document le plus auto-documentant - "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.

Edit: J'ai vérifié la source Python. Si vous passez une chaîne unicode à bytes à l'aide de CPython, il appelle PyUnicode_AsEncodedString , qui est l'implémentation de encode; vous sautez donc un niveau d'indirection si vous appelez vous-même encode.

Voir aussi le commentaire de Serdalis - unicode_string.encode(encoding) est également plus Pythonique car son inverse est byte_string.decode(encoding) et sa symétrie est Nice.

483
agf

C'est plus facile qu'on le pense:

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
244
hasanatkazmi

Le meilleur moyen absolu n'est ni l'un ni l'autre des 2, mais le troisième. Le premier paramètre à encode utilise par défaut la valeur 'utf-8' depuis Python 3.0. Ainsi, le meilleur moyen est

b = mystring.encode()

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

Voici quelques 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

Malgré cet avertissement, les temps étaient très stables après des essais répétés - l'écart n'était que d'environ 2%.


Utiliser encode() sans argument n'est pas Python 2 compatible, comme dans Python 2 l'encodage de 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)
95
Antti Haapala

Vous pouvez simplement convertir une chaîne en octets en utilisant:

a_string.encode()

et vous pouvez simplement convertir des octets en chaîne en utilisant:

some_bytes.decode()

bytes.decode et str.encode ont comme valeur par défaut encoding='utf-8'.

Les fonctions suivantes (extraites de Effective Python ) peuvent être utiles pour convertir str en bytes et bytes en str:

def to_bytes(bytes_or_str):
    if isinstance(bytes_or_str, str):
        value = bytes_or_str.encode() # uses 'utf-8' for encoding
    else:
        value = bytes_or_str
    return value # Instance of bytes


def to_str(bytes_or_str):
    if isinstance(bytes_or_str, bytes):
        value = bytes_or_str.decode() # uses 'utf-8' for encoding
    else:
        value = bytes_or_str
    return value # Instance of str
40
lmiguelvargasf
so_string = 'stackoverflow'
so_bytes = so_string.encode( )
9
gerardw