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.

Masroore
sumber
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'.

Martijn Pieters
sumber
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()
theofpa
sumber
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'>
Suresh
sumber
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

meck373
sumber
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

starter
sumber
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())
Shiv Buyya
sumber
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')
Matan Hugi
sumber
4

mengapa tidak mencoba membuka file Anda sebagai teks?

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

Selain itu di sini adalah tautan untuk python 3.x di halaman resmi: https://docs.python.org/3/library/io.html Dan ini adalah fungsi terbuka: https://docs.python.org/3 /library/functions.html#open

Jika Anda benar-benar mencoba menanganinya sebagai biner maka pertimbangkan untuk menyandikan string Anda.

Fernando D Jaime
sumber
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.

Ibrahim
sumber