TypeError: un objet de type octets est requis, pas 'str' lors de l'écriture dans un fichier en Python3

590

J'ai récemment migré vers Py 3.5. Ce code fonctionnait correctement dans Python 2.7:

with open(fname, 'rb') as f:
    lines = [x.strip() for x in f.readlines()]

for line in lines:
    tmp = line.strip().lower()
    if 'some-pattern' in tmp: continue
    # ... code

Après la mise à niveau vers 3.5, j'obtiens:

TypeError: a bytes-like object is required, not 'str'

erreur sur la dernière ligne (le code de recherche de modèle).

J'ai essayé d'utiliser la .decode()fonction de chaque côté de la déclaration, j'ai également essayé:

if tmp.find('some-pattern') != -1: continue

- en vain.

J'ai pu résoudre presque tous les problèmes 2: 3 rapidement, mais cette petite déclaration me dérange.

masroore
la source
11
Pourquoi ouvrez-vous le fichier en mode binaire mais le traitez-vous comme du texte?
Martijn Pieters
4
@MartijnPieters merci d'avoir repéré le mode d'ouverture de fichier! Le changer en mode texte a résolu le problème ... le code fonctionnait de manière fiable dans Py2k depuis de nombreuses années ...
masroore
10
Je rencontre cela aussi où j'ai des demandes result = requests.getet j'essaye de le faire x = result.content.split("\n"). Je suis un peu confus par le message d'erreur car il semble impliquer qu'il result.contents'agit d'une chaîne et .split()nécessite un objet de type octets .. ?? ("un objet de type octets est requis, pas 'str"').

Réponses:

553

Vous avez ouvert le fichier en mode binaire:

with open(fname, 'rb') as f:

Cela signifie que toutes les données lues dans le fichier sont renvoyées en tant bytesqu'objets, non str. Vous ne pouvez alors pas utiliser une chaîne dans un test de confinement:

if 'some-pattern' in tmp: continue

Vous devez utiliser un bytesobjet pour effectuer un test à la tmpplace:

if b'some-pattern' in tmp: continue

ou ouvrez le fichier en tant que fichier texte à la place en remplaçant le 'rb'mode par 'r'.

Martijn Pieters
la source
12
Si vous jetez un œil aux différents documents auxquels ppl s'est lié, vous verrez que tout "fonctionnait" dans Py2 car les chaînes par défaut étaient des octets alors que dans Py3, les chaînes par défaut sont Unicode, ce qui signifie qu'à chaque fois que vous effectuez des E / S, esp. mise en réseau, les chaînes d'octets sont la norme, vous devez donc apprendre à déplacer les chaînes Unicode et octets n / b (en / décode). Pour les fichiers, nous avons maintenant «r» contre «rb» (et pour «w» et «a») pour aider à différencier.
wescpy
3
@wescpy: Python 2 a aussi des'r' vs , basculant entre les comportements binaires et les fichiers texte (comme la traduction de nouvelles lignes et sur certaines plateformes, la façon dont le marqueur EOF est traité). Le fait que la bibliothèque (fournissant la fonctionnalité d'E / S par défaut dans Python 3 mais également disponible dans Python 2) décode désormais également les fichiers texte par défaut est le vrai changement. 'rb' io
Martijn Pieters
2
@MartijnPieters: Oui, d'accord. Dans 2.x, je n'utilisais l' 'b'indicateur que lorsque je devais travailler avec des fichiers binaires sous DOS / Windows (car le binaire est le POSIX par défaut). Il est bon qu'il y ait un double objectif lors de l'utilisation iodans 3.x pour l'accès aux fichiers.
wescpy
209

Vous pouvez encoder votre chaîne en utilisant .encode()

Exemple:

'Hello World'.encode()
theofpa
la source
48

Comme cela a déjà été mentionné, vous lisez le fichier en mode binaire puis créez une liste d'octets. Dans votre suite pour boucle vous comparez une chaîne à des octets et c'est là que le code échoue.

Le décodage des octets lors de l'ajout à la liste devrait fonctionner. Le code modifié doit se présenter comme suit:

with open(fname, 'rb') as f:
    lines = [x.decode('utf8').strip() for x in f.readlines()]

Le type d'octets a été introduit dans Python 3 et c'est pourquoi votre code fonctionnait dans Python 2. Dans Python 2, il n'y avait pas de type de données pour les octets:

>>> s=bytes('hello')
>>> type(s)
<type 'str'>
Suresh
la source
25

Vous devez passer de wb à w:

def __init__(self):
    self.myCsv = csv.writer(open('Item.csv', 'wb')) 
    self.myCsv.writerow(['title', 'link'])

à

def __init__(self):
    self.myCsv = csv.writer(open('Item.csv', 'w'))
    self.myCsv.writerow(['title', 'link'])

Après avoir changé cela, l'erreur disparaît, mais vous ne pouvez pas écrire dans le fichier (dans mon cas). Donc après tout, je n'ai pas de réponse?

La source: Comment supprimer ^ M

Le passage à «rb» m'apporte l'autre erreur: io.UnsupportedOperation: write

meck373
la source
15

pour ce petit exemple: import socket

mysock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mysock.connect(('www.py4inf.com', 80))
mysock.send(**b**'GET http://www.py4inf.com/code/romeo.txt HTTP/1.0\n\n')

while True:
    data = mysock.recv(512)
    if ( len(data) < 1 ) :
        break
    print (data);

mysock.close()

l'ajout du "b" avant "GET http://www.py4inf.com/code/romeo.txt HTTP / 1.0 \ n \ n" a résolu mon problème

entrée
la source
11

Utilisez la fonction encode () avec la valeur String codée en dur donnée dans un guillemet simple.

Ex:

file.write(answers[i] + '\n'.encode())

OU

line.split(' +++$+++ '.encode())
Shiv Buyya
la source
8

Vous avez ouvert le fichier en mode binaire:

Le code suivant lancera une TypeError: un objet de type octets est requis, pas 'str'.

for line in lines:
    print(type(line))# <class 'bytes'>
    if 'substring' in line:
       print('success')

Le code suivant fonctionnera - vous devez utiliser la fonction decode ():

for line in lines:
    line = line.decode()
    print(type(line))# <class 'str'>
    if 'substring' in line:
       print('success')
Matan Hugi
la source
1

J'ai eu cette erreur lorsque j'essayais de convertir un char (ou une chaîne) en bytes, le code était quelque chose comme ça avec Python 2.7:

# -*- coding: utf-8 -*-
print( bytes('ò') )

C'est la voie de Python 2.7 traite les caractères unicode.

Cela ne fonctionnera pas avec Python 3.6, car bytesnécessite un argument supplémentaire pour l'encodage, mais cela peut être peu délicat, car un encodage différent peut produire un résultat différent:

print( bytes('ò', 'iso_8859_1') ) # prints: b'\xf2'
print( bytes('ò', 'utf-8') ) # prints: b'\xc3\xb2'

Dans mon cas, j'ai dû utiliser iso_8859_1 lors du codage des octets afin de résoudre le problème.

J'espère que cela aide quelqu'un.

Ibrahim.H
la source