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 ?
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 ?
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.
+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.
bytearray
est utilisé lorsque vous avez besoin d'un objet mutable. Vous n'en avez pas besoin pour de simples str``bytes
les conversions.
@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à.
Il sait comment faire, il demande juste quel est le meilleur moyen. Relisez la question, s'il vous plaît.
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.
@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)
.
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)
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) :
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.
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 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.
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.
11 votes
@LennartRegebro Je me sens assez bien pour juste utiliser
bytes(item, "utf8")
comme l'explicite est meilleur que l'implicite, alors...str.encode( )
Par défaut, il s'agit de bytes, ce qui vous rend plus Unicode-zen mais moins Explicit-Zen. De plus, "commun" n'est pas un terme que j'aime suivre. Et aussi,bytes(item, "utf8")
c'est plutôt lestr()
yb"string"
les notations. Je m'excuse si je suis trop novice pour comprendre vos raisons. Merci.5 votes
@erm3nda si vous lisez la réponse acceptée vous pouvez voir que
encode()
n'appelle pasbytes()
c'est l'inverse. Bien sûr, ce n'est pas immédiatement évident, c'est pourquoi j'ai posé la question.0 votes
Doh, désolé. De toute façon, ce que j'ai dit s'applique aussi pour
some_string.encode(encoding)
à titre d'exemple"string".encode("utf8")
qui renvoie des octets de type. Pour moi, l'utilisation du termebytes()
est beaucoup plus logique. J'ai tendance à penser que le codage/décodage est davantage lié au jeu de caractères qu'au type de données. Encore une fois, je suis peut-être trop novice pour penser comme ça... mais j'aime l'explicite, et il n'y a pas de référence à "byte" dans..."some".encode("utf8")
. Merci, j'ai vérifié.str.encode()
n'a pas de défaut.2 votes
Le sens même du mot "encoder" dans le contexte du texte n'inclut-il pas celui d'"octets", car l'encodage du texte consiste à prendre des données textuelles abstraites et à les transformer en une représentation concrète d'octets ?
1 votes
Encode et decode sont toujours préférés car le chaînage est plus facile à lire que l'imbrication, par exemple ebcdic=passed.decode('utf-8').encode('ibm500')
0 votes
Le 'utf-8' est la valeur par défaut, donc la réponse la plus simple est
b = mystring.encode( )