TypeError: è richiesto un oggetto simile a byte, non 'str' quando si scrive su un file in Python3


590

Di recente sono migrato su Py 3.5. Questo codice funzionava correttamente in 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

Dopo l'aggiornamento a 3.5, sto ottenendo il:

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

errore sull'ultima riga (il codice di ricerca del modello).

Ho provato a usare la .decode()funzione su entrambi i lati della frase, ho anche provato:

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

- inutilmente.

Sono stato in grado di risolvere rapidamente quasi tutti i problemi 2: 3, ma questa piccola affermazione mi sta infastidendo.


11
Perché stai aprendo il file in modalità binaria ma lo tratti come testo?
Martijn Pieters

4
@MartijnPieters grazie per aver individuato la modalità di apertura del file! Il passaggio alla modalità testo ha risolto il problema ... il codice aveva funzionato in modo affidabile in Py2k per molti anni ...
Masroore,


10
Lo sto incontrando anche dove ho delle richieste result = requests.gete cerco di farlo x = result.content.split("\n"). Sono un po 'confuso dal messaggio di errore perché sembra implicare che result.contentè una stringa e .split()richiede un oggetto simile a byte .. ?? ("è richiesto un oggetto simile a byte, non 'str"') ..

Risposte:


553

Hai aperto il file in modalità binaria:

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

Ciò significa che tutti i dati letti dal file vengono restituiti come bytesoggetti, non str. Non è quindi possibile utilizzare una stringa in un test di contenimento:

if 'some-pattern' in tmp: continue

Dovresti usare un bytesoggetto per testare tmpinvece:

if b'some-pattern' in tmp: continue

oppure apri il file come file di testo invece sostituendo la 'rb'modalità con 'r'.


12
Se dai un'occhiata ai vari documenti a cui ppl è collegato, noterai che tutto "ha funzionato" in Py2 perché le stringhe predefinite erano byte mentre in Py3, le stringhe predefinite sono Unicode, il che significa che ogni volta che esegui I / O, esp. rete, le stringhe di byte sono lo standard, quindi è necessario imparare a spostare le stringhe Unicode e byte (en / decodifica). Per i file, ora abbiamo "r" vs. "rb" (e per 'w' & 'a') per aiutare a differenziare.
wescpy

3
@wescpy: Python 2 ha 'r'vs 'rb' troppo , il passaggio tra i comportamenti di file binari e di testo (come a capo traduzione e su alcune piattaforme, come viene trattato l'indicatore EOF). Che la iolibreria (che fornisce la funzionalità I / O predefinita in Python 3 ma disponibile anche in Python 2) ora decodifica anche i file di testo per impostazione predefinita è la vera modifica.
Martijn Pieters

2
@MartijnPieters: Sì, d'accordo. In 2.x, ho usato il 'b'flag solo quando ho dovuto lavorare con file binari su DOS / Windows (dato che binario è l'impostazione predefinita POSIX). È positivo che vi sia un duplice scopo quando si utilizza ioin 3.x per l'accesso ai file.
wescpy

209

Puoi codificare la tua stringa usando .encode()

Esempio:

'Hello World'.encode()

48

Come è già stato menzionato, stai leggendo il file in modalità binaria e quindi creando un elenco di byte. Nel tuo seguito per ciclo stai confrontando la stringa con i byte ed è qui che il codice non riesce.

La decodifica dei byte durante l'aggiunta all'elenco dovrebbe funzionare. Il codice modificato dovrebbe apparire come segue:

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

Il tipo di byte è stato introdotto in Python 3 ed è per questo che il codice ha funzionato in Python 2. In Python 2 non esisteva un tipo di dati per byte:

>>> s=bytes('hello')
>>> type(s)
<type 'str'>

25

Devi cambiare da wb a w:

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

per

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

Dopo averlo modificato, l'errore scompare, ma non è possibile scrivere sul file (nel mio caso). Quindi, dopo tutto, non ho una risposta?

Fonte: come rimuovere ^ M

Passare a 'rb' mi porta l'altro errore: io.UnsupportedOperation: write


15

per questo piccolo esempio: 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()

aggiungendo la "b" prima di 'GET http://www.py4inf.com/code/romeo.txt HTTP / 1.0 \ n \ n' risolto il mio problema


11

Utilizzare la funzione encode () insieme al valore String codificato indicato in una singola virgoletta.

Ex:

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

O

line.split(' +++$+++ '.encode())

8

Hai aperto il file in modalità binaria:

Il codice seguente genererà un TypeError: è richiesto un oggetto di tipo byte, non 'str'.

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

Il seguente codice funzionerà: devi usare la funzione decode ():

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


1

Ho avuto questo errore quando stavo cercando di convertire un carattere (o una stringa) in bytes, il codice era qualcosa del genere con Python 2.7:

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

Questo è il modo di Python 2.7 quando si tratta di caratteri unicode.

Questo non funzionerà con Python 3.6, poiché bytesrichiede un argomento aggiuntivo per la codifica, ma questo può essere un po 'complicato, poiché una codifica diversa può produrre risultati diversi:

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

Nel mio caso, ho dovuto utilizzare la iso_8859_1codifica dei byte per risolvere il problema.

Spero che questo aiuti qualcuno.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.