TypeError: objek byte-seperti diperlukan, bukan 'str' saat menulis ke file di Python3


590

Saya baru-baru ini pindah ke Py 3.5. Kode ini berfungsi dengan baik di 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

Setelah meningkatkan ke 3.5, saya mendapatkan:

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

kesalahan pada baris terakhir (kode pencarian pola).

Saya sudah mencoba menggunakan .decode()fungsi di kedua sisi pernyataan, juga mencoba:

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

- tidak berhasil.

Saya dapat menyelesaikan hampir semua masalah 2: 3 dengan cepat, tetapi pernyataan kecil ini menggangguku.


11
Mengapa Anda membuka file dalam mode biner tetapi memperlakukannya sebagai teks?
Martijn Pieters

4
@ MartijnPieters terima kasih telah melihat mode buka file! Mengubahnya ke mode teks memecahkan masalah ... kode telah bekerja andal di Py2k selama bertahun-tahun meskipun ...
masroore


10
Saya juga menghadapi ini di mana saya memiliki permintaan result = requests.getdan saya berusaha x = result.content.split("\n"). Saya sedikit bingung dengan pesan kesalahan karena tampaknya menyiratkan bahwa itu result.contentadalah string dan .split()memerlukan objek byte-suka .. ?? ("objek seperti byte diperlukan, bukan 'str"') ..

Jawaban:


553

Anda membuka file dalam mode biner:

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

Ini berarti bahwa semua data yang dibaca dari file dikembalikan sebagai bytesobjek, bukan str. Kemudian Anda tidak dapat menggunakan string dalam uji penahanan:

if 'some-pattern' in tmp: continue

Anda harus menggunakan bytesobjek untuk diuji tmpsebagai gantinya:

if b'some-pattern' in tmp: continue

atau buka file sebagai file teks sebagai gantinya dengan mengganti 'rb'mode dengan 'r'.


12
Jika Anda mengintip berbagai dokumen yang telah ditautkan oleh ppl, Anda akan melihat bahwa semuanya "berfungsi" di Py2 karena string default adalah byte sedangkan di Py3, string default adalah Unicode, artinya setiap kali Anda melakukan I / O, esp. jaringan, string byte adalah standar, jadi Anda harus belajar untuk memindahkan string Unicode & byte (en / decode). Untuk file, kami sekarang memiliki "r" vs. "rb" (dan untuk 'w' & 'a') untuk membantu membedakan.
wescpy

3
@wescpy: Python 2 memiliki 'r'vs 'rb' terlalu , beralih antara perilaku file biner dan teks (seperti menerjemahkan baris dan pada platform tertentu, bagaimana penanda EOF diperlakukan). Bahwa ioperpustakaan (menyediakan fungsionalitas I / O default di Python 3 tetapi juga tersedia di Python 2) sekarang juga menerjemahkan file teks secara default adalah perubahan nyata.
Martijn Pieters

2
@ MartijnPieters: Ya, setuju. Dalam 2.x, saya hanya menggunakan 'b'flag ketika harus bekerja dengan file biner pada DOS / Windows (sebagai biner adalah POSIX default). Ada baiknya ada tujuan ganda saat menggunakan iodi 3.x untuk akses file.
wescpy

209

Anda dapat menyandikan string Anda dengan menggunakan .encode()

Contoh:

'Hello World'.encode()

48

Seperti yang telah disebutkan, Anda membaca file dalam mode biner dan kemudian membuat daftar byte. Dalam mengikuti Anda untuk loop Anda membandingkan string dengan byte dan di situlah kode gagal.

Decoding byte sambil menambahkan ke daftar harus berfungsi. Kode yang diubah akan terlihat sebagai berikut:

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

Tipe byte diperkenalkan di Python 3 dan itulah sebabnya kode Anda bekerja di Python 2. Dalam Python 2 tidak ada tipe data untuk byte:

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

25

Anda harus mengubah dari wb ke w:

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

untuk

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

Setelah mengubah ini, kesalahannya hilang, tetapi Anda tidak dapat menulis ke file (dalam kasus saya). Jadi, bagaimanapun juga, saya tidak punya jawaban?

Sumber: Cara menghapus ^ M

Mengubah ke 'rb' membawa saya kesalahan lain: io.UnsupportedOperation: write


15

untuk contoh kecil ini: 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()

menambahkan "b" sebelum 'GET http://www.py4inf.com/code/romeo.txt HTTP / 1.0 \ n \ n' memecahkan masalah saya


11

Gunakan fungsi encode () bersama dengan nilai String hardcoded yang diberikan dalam kutipan tunggal.

Ex:

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

ATAU

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

8

Anda membuka file dalam mode biner:

Kode berikut akan melempar TypeError: diperlukan objek seperti byte, bukan 'str'.

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

Kode berikut akan berfungsi - Anda harus menggunakan fungsi decode ():

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


1

Saya mendapatkan kesalahan ini ketika saya mencoba mengonversi char (atau string) menjadi bytes, kodenya seperti ini dengan Python 2.7:

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

Ini adalah cara Python 2.7 ketika berhadapan dengan karakter unicode.

Ini tidak akan berfungsi dengan Python 3.6, karena bytesmemerlukan argumen tambahan untuk penyandian, tetapi ini bisa sedikit rumit, karena penyandian yang berbeda dapat menghasilkan hasil yang berbeda:

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

Dalam kasus saya, saya harus menggunakan iso_8859_1ketika encoding byte untuk menyelesaikan masalah.

Semoga ini bisa membantu seseorang.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.