TypeError: Beim Schreiben in eine Datei in Python3 ist ein byteähnliches Objekt erforderlich, nicht 'str'

590

Ich bin kürzlich auf Py 3.5 migriert. Dieser Code funktionierte in Python 2.7 ordnungsgemäß:

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

Nach dem Upgrade auf 3.5 erhalte ich Folgendes:

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

Fehler in der letzten Zeile (der Mustersuchcode).

Ich habe versucht, die .decode()Funktion auf beiden Seiten der Anweisung zu verwenden. Außerdem habe ich versucht:

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

- umsonst.

Ich konnte fast alle 2: 3-Probleme schnell lösen, aber diese kleine Aussage nervt mich.

masroore
quelle
11
Warum öffnen Sie die Datei im Binärmodus, behandeln sie aber als Text?
Martijn Pieters
4
@MartijnPieters, danke, dass du den Modus zum Öffnen von Dateien entdeckt hast! Das Ändern in den Textmodus löste das Problem ... der Code hatte jedoch viele Jahre in Py2k zuverlässig funktioniert ...
masroore
10
Ich begegne dem auch dort, wo ich Anfragen habe result = requests.getund es versuche x = result.content.split("\n"). Ich bin ein wenig verwirrt von der Fehlermeldung, weil es zu implizieren scheint, dass result.contentes sich um eine Zeichenfolge .split()handelt und ein byteähnliches Objekt erforderlich ist. ("ein

Antworten:

553

Sie haben die Datei im Binärmodus geöffnet:

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

Dies bedeutet, dass alle aus der Datei gelesenen Daten als bytesObjekte zurückgegeben werden, nicht str. Sie können dann keine Zeichenfolge in einem Containment-Test verwenden:

if 'some-pattern' in tmp: continue

Sie müssten stattdessen ein bytesObjekt zum Testen tmpverwenden:

if b'some-pattern' in tmp: continue

oder öffnen Sie die Datei stattdessen als Textdatei, indem Sie den 'rb'Modus durch ersetzen 'r'.

Martijn Pieters
quelle
12
Wenn Sie sich die verschiedenen Dokumente ansehen, mit denen ppl verknüpft ist, werden Sie feststellen, dass in Py2 alles "funktioniert" hat, da Standardzeichenfolgen Bytes waren, während in Py3 Standardzeichenfolgen Unicode sind. insb. Netzwerk, Byte-Strings sind der Standard, daher müssen Sie lernen, s / w Unicode- und Byte-Strings (en / decode) zu verschieben. Für Dateien haben wir jetzt "r" vs. "rb" (und für 'w' & 'a'), um die Unterscheidung zu erleichtern.
wescpy
3
@wescpy: Python 2 hat 'r'vs 'rb' zu , das Umschalten zwischen Binär- und Textdatei Verhalten (wie das Übersetzen Zeilenumbrüche und auf bestimmten Plattformen, wie die EOF - Markierung behandelt wird). Dass die ioBibliothek (die die Standard-E / A-Funktionalität in Python 3 bereitstellt, aber auch in Python 2 verfügbar ist) jetzt auch standardmäßig Textdateien dekodiert, ist die eigentliche Änderung.
Martijn Pieters
2
@MartijnPieters: Ja, stimmte zu. In 2.x habe ich das 'b'Flag nur verwendet, wenn ich unter DOS / Windows mit Binärdateien arbeiten musste (da Binär die POSIX-Standardeinstellung ist). Es ist gut, dass es einen doppelten Zweck gibt, wenn ioin 3.x für den Dateizugriff verwendet wird.
wescpy
208

Sie können Ihre Zeichenfolge mit codieren .encode()

Beispiel:

'Hello World'.encode()
theofpa
quelle
48

Wie bereits erwähnt, lesen Sie die Datei im Binärmodus und erstellen dann eine Liste von Bytes. In Ihrer folgenden for- Schleife vergleichen Sie Zeichenfolgen mit Bytes, und hier schlägt der Code fehl.

Das Dekodieren der Bytes beim Hinzufügen zur Liste sollte funktionieren. Der geänderte Code sollte wie folgt aussehen:

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

Der Bytetyp wurde in Python 3 eingeführt, und deshalb funktionierte Ihr Code in Python 2. In Python 2 gab es keinen Datentyp für Bytes:

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

Sie müssen von wb zu w wechseln:

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

zu

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

Nachdem Sie dies geändert haben, verschwindet der Fehler, aber Sie können nicht in die Datei schreiben (in meinem Fall). Also habe ich doch keine Antwort?

Quelle: So entfernen Sie ^ M.

Das Ändern zu 'rb' bringt mir den anderen Fehler: io.UnsupportedOperation: write

meck373
quelle
15

für dieses kleine Beispiel: Socket importieren

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()

Das Hinzufügen des "b" vor "GET http://www.py4inf.com/code/romeo.txt HTTP / 1.0 \ n \ n" löste mein Problem

Anlasser
quelle
11

Verwenden Sie die Funktion encode () zusammen mit dem fest codierten String-Wert in einem einfachen Anführungszeichen.

Ex:

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

ODER

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

Sie haben die Datei im Binärmodus geöffnet:

Der folgende Code löst einen TypeError aus: Ein byteähnliches Objekt ist erforderlich, nicht 'str'.

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

Der folgende Code funktioniert - Sie müssen die Funktion decode () verwenden:

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

Warum nicht versuchen, Ihre Datei als Text zu öffnen?

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

Zusätzlich gibt es hier einen Link für Python 3.x auf der offiziellen Seite: https://docs.python.org/3/library/io.html Und dies ist die offene Funktion: https://docs.python.org/3 /library/functions.html#open

Wenn Sie wirklich versuchen, es als Binärdatei zu behandeln, sollten Sie Ihre Zeichenfolge codieren.

Fernando D Jaime
quelle
1

Ich habe diesen Fehler erhalten, als ich versucht habe, ein Zeichen (oder einen String) in zu konvertieren. bytesDer Code war mit Python 2.7 ungefähr so:

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

Dies ist der Weg von Python 2.7 beim Umgang mit Unicode-Zeichen.

Dies funktioniert mit Python 3.6 nicht, da bytesein zusätzliches Argument für die Codierung erforderlich ist. Dies kann jedoch etwas schwierig sein, da unterschiedliche Codierungen unterschiedliche Ergebnisse liefern können:

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

In meinem Fall musste ich iso_8859_1beim Codieren von Bytes verwenden, um das Problem zu lösen.

Hoffe das hilft jemandem.

Ibrahim.H
quelle