TypeError: bắt buộc phải có một đối tượng giống byte, chứ không phải 'str' khi ghi vào tệp trong Python3


590

Gần đây tôi đã di chuyển đến Py 3.5. Mã này đã hoạt động đúng trong 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

Sau khi nâng cấp lên 3.5, tôi nhận được:

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

lỗi trên dòng cuối cùng (mã tìm kiếm mẫu).

Tôi cũng đã thử sử dụng .decode()chức năng ở hai bên của câu lệnh, cũng đã thử:

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

- vô ích.

Tôi đã có thể giải quyết gần như tất cả các vấn đề 2: 3 một cách nhanh chóng, nhưng tuyên bố nhỏ này đang làm tôi khó chịu.


11
Tại sao bạn mở tệp ở chế độ nhị phân nhưng coi nó là văn bản?
Martijn Pieters

4
@MartijnPieters cảm ơn vì đã phát hiện ra chế độ mở tệp! Thay đổi nó thành chế độ văn bản đã giải quyết được vấn đề ... mã đã hoạt động đáng tin cậy ở Py2k trong nhiều năm qua ...
masroore


10
Tôi cũng gặp phải điều này khi tôi có một yêu cầu result = requests.getvà tôi cố gắng x = result.content.split("\n"). Tôi hơi bối rối bởi thông báo lỗi bởi vì nó dường như ngụ ý đó result.contentlà một chuỗi và .split()đang yêu cầu một đối tượng giống như byte .. ?? ("một đối tượng giống byte là bắt buộc, không phải 'str"') ..

Câu trả lời:


553

Bạn đã mở tệp ở chế độ nhị phân:

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

Điều này có nghĩa là tất cả dữ liệu đọc từ tệp được trả về dưới dạng bytesđối tượng, không phải str. Sau đó, bạn không thể sử dụng một chuỗi trong kiểm tra ngăn chặn:

if 'some-pattern' in tmp: continue

Thay vào đó, bạn phải sử dụng một bytesđối tượng để kiểm tra lại tmp:

if b'some-pattern' in tmp: continue

hoặc mở tệp dưới dạng tệp văn bản thay thế bằng cách thay thế 'rb'chế độ bằng 'r'.


12
Nếu bạn xem qua các tài liệu khác nhau mà ppl đã liên kết đến, bạn sẽ thấy mọi thứ "hoạt động" trong Py2 vì các chuỗi mặc định là byte trong khi ở Py3, các chuỗi mặc định là Unicode, nghĩa là bất cứ khi nào bạn thực hiện I / O, đặc biệt mạng, chuỗi byte là tiêu chuẩn, vì vậy bạn phải học cách di chuyển chuỗi b / w Unicode & byte (en / decode). Đối với các tệp, chúng tôi hiện có "r" so với "rb" (và cho 'w' & 'a') để giúp phân biệt.
wescpy

3
@wescpy: Python 2 có 'r'vs 'rb' quá , chuyển đổi giữa các hành vi tập tin nhị phân và văn bản (như newlines dịch và trên nền tảng nhất định, cách thức đánh dấu EOF được xử lý). Rằng iothư viện (cung cấp chức năng I / O mặc định trong Python 3 nhưng cũng có sẵn trong Python 2) giờ đây cũng giải mã các tệp văn bản theo mặc định là thay đổi thực sự.
Martijn Pieters

2
@MartijnPieters: Vâng, đã đồng ý. Trong 2.x, tôi chỉ sử dụng 'b'cờ khi phải làm việc với các tệp nhị phân trên DOS / Windows (vì nhị phân là mặc định POSIX). Thật tốt khi có một mục đích kép khi sử dụng iotrong 3.x để truy cập tệp.
wescpy

208

Bạn có thể mã hóa chuỗi của mình bằng cách sử dụng .encode()

Thí dụ:

'Hello World'.encode()

48

Giống như nó đã được đề cập, bạn đang đọc tệp ở chế độ nhị phân và sau đó tạo một danh sách các byte. Trong vòng lặp sau đây của bạn, bạn đang so sánh chuỗi với byte và đó là nơi mã bị lỗi.

Giải mã các byte trong khi thêm vào danh sách sẽ hoạt động. Mã đã thay đổi sẽ trông như sau:

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

Kiểu byte được giới thiệu trong Python 3 và đó là lý do tại sao mã của bạn hoạt động trong Python 2. Trong Python 2 không có loại dữ liệu cho byte:

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

25

Bạn phải thay đổi từ wb sang w:

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

đến

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

Sau khi thay đổi, lỗi sẽ biến mất, nhưng bạn không thể ghi vào tệp (trong trường hợp của tôi). Vì vậy, sau tất cả, tôi không có câu trả lời?

Nguồn: Cách xóa ^ M

Thay đổi thành 'rb' mang đến cho tôi một lỗi khác: io.UnsupportedOperation: write


15

cho ví dụ nhỏ này: ổ cắm nhập khẩu

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

việc thêm "b" vào trước 'NHẬN http://www.py4inf.com/code/romeo.txt HTTP / 1.0 \ n \ n' đã giải quyết vấn đề của tôi


11

Sử dụng hàm encode () cùng với giá trị Chuỗi được mã hóa cứng được đưa ra trong một trích dẫn.

Ví dụ:

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

HOẶC LÀ

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

8

Bạn đã mở tệp ở chế độ nhị phân:

Đoạn mã sau sẽ đưa ra TypeError: một đối tượng giống byte được yêu cầu, không phải 'str'.

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

Đoạn mã sau sẽ hoạt động - bạn phải sử dụng hàm decode ():

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

4

Tại sao không thử mở tập tin của bạn dưới dạng văn bản?

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

Ngoài ra, đây là một liên kết cho python 3.x trên trang chính thức: https://docs.python.org/3/l Library / io.html Và đây là chức năng mở: https://docs.python.org/3 / l Library / fiances.html # open

Nếu bạn thực sự đang cố gắng xử lý nó như một nhị phân thì hãy xem xét mã hóa chuỗi của bạn.


1

Tôi đã gặp lỗi này khi tôi đang cố gắng chuyển đổi một char (hoặc chuỗi) thành bytes, mã giống như thế này với Python 2.7:

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

Đây là cách của Python 2.7 khi xử lý các ký tự unicode.

Điều này sẽ không hoạt động với Python 3.6, vì bytesyêu cầu thêm một đối số để mã hóa, nhưng điều này có thể hơi khó, vì mã hóa khác nhau có thể tạo ra kết quả khác nhau:

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

Trong trường hợp của tôi, tôi đã phải sử dụng iso_8859_1khi mã hóa byte để giải quyết vấn đề.

Hy vọng điều này sẽ giúp được ai đó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.