HOWTO · Python

Corriger l'erreur Bytes-Like Object Is Required Not STR en Python

Ce tutoriel traite de l'erreur bytes-like object is required not str en Python.

Sur cette page

Le TypeError Python « a bytes-like object is required, not ‘str’ » signifie qu’une opération attend des octets, mais a reçu du texte (str). Examinez la valeur au moment de l’appel qui échoue, puis adaptez l’opération aux données : encodez le texte si l’API attend des octets, ou décodez les octets si vous devez traiter du texte.

Comprendre le TypeError « bytes-like object is required, not ‘str’ »

Le message indique les deux côtés de l’incompatibilité. « Bytes-like object is required » précise la valeur acceptée par l’opération ; « not ‘str’ » indique que la valeur fournie était du texte. Cette erreur apparaît souvent lors d’une opération sur un séparateur, de l’écriture dans un fichier binaire ou de l’envoi sur une socket. Repérez l’appel concerné, puis remontez jusqu’à l’endroit où son argument a été lu, créé ou converti.

Pourquoi le texte et les données binaires sont incompatibles

En Python 3, str représente du texte : une suite de caractères Unicode. bytes est une séquence immuable de valeurs d’octet, souvent utilisée pour le texte encodé, les fichiers et les données réseau. Ce sont des types différents et ils ne sont pas interchangeables, même lorsque les octets représentent des caractères lisibles.

L’encodage transforme le texte en octets selon un encodage de caractères, tel que UTF-8. Le décodage interprète des octets comme du texte à l’aide de l’encodage correspondant. Le choix dépend du sens des données et du type accepté par l’API destinataire ; une conversion faite à l’aveugle peut masquer l’incompatibilité ou altérer les données. Les conventions sur les chaînes étaient différentes en Python 2 : ne vous appuyez pas sur son comportement pour raisonner sur du code Python 3.

Convertir le texte et les octets à la frontière entre les deux

Utilisez encode() sur du texte lorsqu’il est transmis à une API qui exige des octets. Utilisez decode() sur des octets lorsque vous passez au traitement de texte, en choisissant l’encodage correspondant à celui qui a servi à produire ces octets.

La transformation est explicite : le code montre à quel endroit le texte devient des octets, puis à quel endroit ceux-ci redeviennent du texte. UTF-8 est un choix courant pour le texte à stocker ou à envoyer dans un format portable. Conservez la valeur sous sa forme d’origine tant que vous ne connaissez pas le type attendu par l’opération suivante. Vous pourrez ainsi repérer plus facilement une incompatibilité et éviter de traiter du contenu binaire comme s’il s’agissait de texte.

Exécutez cet exemple :

Le code et les libellés ou sorties affichés dans cette section restent en anglais.

text = "Hello, World!"
data = text.encode("utf-8")
print(data)
print(data.decode("utf-8"))
b'Hello, World!'
Hello, World!

Le préfixe b sur la première ligne de sortie indique une valeur bytes. Appeler str(data) n’inverse pas l’encodage : cette opération ne décode pas le contenu des octets et peut afficher une représentation telle que b'Hello, World!'. Utilisez data.decode("utf-8") si les octets contiennent du texte UTF-8 et que l’opération suivante attend une valeur str.

Corriger l’erreur dans le code des fichiers et des sockets

Un fichier ouvert en mode binaire renvoie ou accepte des valeurs bytes ; en mode texte, le décodage ou l’encodage est effectué automatiquement. Pour du contenu binaire, conservez la valeur en octets et utilisez un séparateur de type bytes, par exemple parts = data.split(b","). Si le fichier contient du texte UTF-8 que vous devez traiter comme du texte, décodez-le d’abord et utilisez un séparateur textuel : parts = data.decode("utf-8").split(","). N’enveloppez pas la lecture d’octets dans str() en pensant que cela décodera le fichier.

La même frontière entre les types s’applique aux méthodes de socket qui travaillent avec des octets. sock.sendall(b"hello") transmet directement des octets. Si le message est d’abord du texte, encodez-le explicitement, par exemple avec sock.sendall(message.encode("utf-8")). Cela décrit le type de l’argument ; un échange réel dépend aussi d’une socket connectée et du protocole utilisé par le pair.

Vérifier la valeur avant de choisir une conversion

Au niveau de l’opération qui échoue, examinez type(value) ou utilisez isinstance(value, bytes) et isinstance(value, str). Vérifiez ensuite le type attendu par l’API, déterminez si la valeur représente du texte ou des données binaires arbitraires, puis convertissez-la une seule fois à cette frontière. Pour du texte, choisissez l’encodage utilisé par le fichier ou le protocole ; pour des données binaires arbitraires, conservez les octets et adaptez le séparateur ou l’opération pour qu’elle accepte des octets. Vous corrigerez ainsi l’incompatibilité sans vous fier à l’apparence de la valeur affichée.