TypeError: Python3'te bir dosyaya yazarken 'str' değil, bayt benzeri bir nesne gerekli


590

Çok yakın zamanda Py 3.5'e taşındım. Bu kod Python 2.7'de düzgün çalışıyordu:

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

3.5 sürümüne geçtikten sonra:

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

son satırda hata (kalıp arama kodu).

Ben .decode()deyim her iki tarafında işlevini kullanarak denedim , ayrıca çalıştı:

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

- boşuna.

Hemen hemen tüm 2: 3 sorunlarını hızlı bir şekilde çözebildim, ancak bu küçük ifade beni rahatsız ediyor.


11
Dosyayı neden ikili modda açıyorsunuz ancak metin olarak değerlendiriyorsunuz?
Martijn Pieters

4
@MartijnPieters dosya açma modunu tespit ettiğiniz için teşekkürler! Metin moduna geçmek sorunu çözdü ... kod Py2k'te uzun yıllar güvenilir bir şekilde çalıştı ...
masroore


10
Ben de bir istek var result = requests.getve ben denemek burada karşılaşıyorum x = result.content.split("\n"). Bu result.contentbir dize ve .split()bayt benzeri bir nesne gerektirir ima gibi görünüyor çünkü hata mesajı ile biraz karışık .. ?? ("bayt benzeri bir nesne gereklidir," str "değil).

Yanıtlar:


553

Dosyayı ikili modda açtınız:

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

Bu, dosyadan okunan tüm verilerin bytesnesne olarak döndürülmediği anlamına gelir str. Ardından, sınırlama testinde bir dize kullanamazsınız:

if 'some-pattern' in tmp: continue

Bunun yerine bytestest etmek için bir nesne kullanmanız gerekir tmp:

if b'some-pattern' in tmp: continue

veya 'rb'modu yerine metin dosyası olarak dosyayı açın 'r'.


12
Ppl'nin bağlandığı çeşitli belgelere bakarsanız, varsayılan dizeler bayt olduğu için Py2'de her şeyin "işe yaradığını" görürsünüz, Py3'te varsayılan dizeler Unicode'dur, yani her zaman G / Ç yaptığınızda, eSP. ağ, bayt dizeleri standarttır, bu nedenle b / w Unicode ve bayt dizelerini (en / decode) taşımayı öğrenmelisiniz. Dosyalar için, artık "r" ve "rb" (ve 'w' & 'a' için) var.
wescpy

3
@wescpy: Python 2 sahiptir 'r'vs 'rb' çok (EOF işaretleyici tedavi edilir nasıl tercüme satırbaşıyla gibi ve belli platformlarda), ikili ve metin dosyası davranışları arasında geçiş. Yani io(Python 2 varsayılan I / O Python 3'te işlevselliği aynı zamanda mevcut sağlayarak) kütüphane şimdi de deşifre varsayılan olarak metin dosyaları gerçek değişimdir.
Martijn Pieters

2
@MartijnPieters: Evet, kabul etti. 2.x, ben sadece 'b'DOS / Windows (ikili POSIX varsayılan olduğu gibi) ikili dosyaları ile çalışmak zorunda bayrak kullandım . ioDosya erişimi için 3.x'te kullanıldığında ikili bir amaç olması iyidir .
wescpy

208

Kullanarak dizenizi kodlayabilirsiniz .encode()

Misal:

'Hello World'.encode()

48

Daha önce de belirtildiği gibi, dosyayı ikili modda okuyorsunuz ve ardından bir bayt listesi oluşturuyorsunuz. Aşağıdaki döngü için dizeyi bayt ile karşılaştırıyorsunuz ve kod başarısız oluyor.

Listeye eklerken baytların kodunun çözülmesi gerekir. Değiştirilen kod aşağıdaki gibi görünmelidir:

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

Bayt türü Python 3'te tanıtıldı ve bu nedenle kodunuz Python 2'de çalıştı. Python 2'de baytlar için veri türü yoktu:

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

25

Wb'den w'ye değiştirmek zorundasınız:

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

için

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

Bunu değiştirdikten sonra hata kaybolur, ancak dosyaya yazamazsınız (benim durumumda). Sonuçta, bir cevabım yok mu?

Kaynak: ^ M nasıl kaldırılır

'Rb' olarak değiştirmek bana diğer hatayı getiriyor: io.UnsupportedOperation: write


15

bu küçük örnek için: 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()

http://www.py4inf.com/code/romeo.txt HTTP / 1.0 \ n \ n 'ALMADAN "b" eklemek sorunumu çözdü


11

Tek bir alıntıda verilen sabit kodlanmış String değeriyle birlikte encode () işlevini kullanın.

Ör:

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

VEYA

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

8

Dosyayı ikili modda açtınız:

Aşağıdaki kod bir TypeError atar: bayt benzeri bir nesne gereklidir, 'str' değil.

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

Aşağıdaki kod çalışır - decode () işlevini kullanmanız gerekir:

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


1

Bir char (veya dize) dönüştürmek için çalışırken bu hatayı aldım bytes, kod Python 2.7 ile böyle bir şey oldu:

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

Unicode karakterlerle uğraşırken Python 2.7'nin yolu budur .

Bu, Python 3.6 ile çalışmaz, çünkü byteskodlama için ekstra bir argüman gerektirir, ancak farklı kodlama farklı sonuçlar verebileceğinden bu biraz zor olabilir:

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

Benim durumumda iso_8859_1, sorunu çözmek için baytları kodlarken kullanmak zorunda kaldım .

Umarım bu birine yardımcı olur.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.