TypeError: จำเป็นต้องมีวัตถุคล้ายไบต์ไม่ใช่ 'str' เมื่อเขียนไปยังไฟล์ใน Python3


590

ฉันเพิ่งย้ายไป Py 3.5 รหัสนี้ทำงานอย่างถูกต้องใน 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

หลังจากอัปเกรดเป็น 3.5 ฉันได้รับ:

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

ข้อผิดพลาดในบรรทัดสุดท้าย (รหัสการค้นหารูปแบบ)

ฉันได้ลองใช้.decode()ฟังก์ชั่นทั้งสองข้างของคำสั่งแล้วลอง:

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

- ไม่มีประโยชน์

ฉันสามารถแก้ไขปัญหา 2: 3 เกือบทั้งหมดได้อย่างรวดเร็ว แต่ข้อความเล็กน้อยนี้ทำให้ฉันรำคาญ


11
เหตุใดคุณจึงเปิดไฟล์ในโหมดไบนารี แต่ถือว่าเป็นข้อความ
Martijn Pieters

4
@MartijnPieters ขอบคุณสำหรับการจำโหมดเปิดไฟล์! การเปลี่ยนเป็นโหมดข้อความช่วยแก้ปัญหา ... โค้ดทำงานได้อย่างน่าเชื่อถือใน Py2k มาเป็นเวลาหลายปีแม้ว่า ...
masroore


10
ฉันกำลังเผชิญหน้านี้มากเกินไปที่ฉันมีการร้องขอและฉันพยายามที่จะresult = requests.get x = result.content.split("\n")ฉันสับสนเล็กน้อยจากข้อความแสดงข้อผิดพลาดเพราะดูเหมือนว่าจะแปลว่าresult.contentเป็นสตริงและ.split()ต้องการวัตถุแบบไบต์ .. ("จำเป็นต้องมีวัตถุคล้ายไบต์ไม่ใช่ 'str"') ..

คำตอบ:


553

คุณเปิดไฟล์ในโหมดไบนารี:

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

ซึ่งหมายความว่าข้อมูลทั้งหมดอ่านจากแฟ้มถูกส่งกลับเป็นวัตถุไม่ได้bytes strจากนั้นคุณไม่สามารถใช้สตริงในการทดสอบการบรรจุ:

if 'some-pattern' in tmp: continue

คุณต้องใช้bytesวัตถุเพื่อทดสอบtmpแทน:

if b'some-pattern' in tmp: continue

หรือเปิดแฟ้มเป็น textfile แทนโดยการเปลี่ยนโหมดที่มี'rb''r'


12
หากคุณดูที่เอกสารต่าง ๆ ที่ ppl เชื่อมโยงไปคุณจะเห็นว่าทุกอย่าง "ทำงาน" ใน Py2 เพราะสตริงเริ่มต้นเป็นไบต์ในขณะที่ Py3 สตริงเริ่มต้นคือ Unicode ซึ่งหมายความว่าทุกครั้งที่คุณทำ I / O ESP เครือข่ายสตริงไบต์เป็นมาตรฐานดังนั้นคุณต้องเรียนรู้ที่จะย้ายสตริง b / w Unicode & ไบต์ (en / ถอดรหัส) สำหรับไฟล์ตอนนี้เรามี "r" กับ "rb" (และสำหรับ 'w' & 'a') เพื่อช่วยแยกความแตกต่าง
wescpy

3
@wescpy: งูหลาม 2 มี'r'VS 'rb' เกินไปสลับระหว่างพฤติกรรมไฟล์ไบนารีและข้อความ (เช่นแปลบรรทัดใหม่และบนแพลตฟอร์มบางวิธีเครื่องหมาย EOF ได้รับการปฏิบัติ) ที่ioห้องสมุด (ให้ฟังก์ชั่นเริ่มต้น I / O ใน Python 3 แต่ยังมีอยู่ใน Python 2) ตอนนี้ยังถอดรหัสไฟล์ข้อความโดยค่าเริ่มต้นคือการเปลี่ยนแปลงที่แท้จริง
Martijn Pieters

2
@MartijnPieters: ใช่เห็นด้วย ใน 2.x ฉันใช้การ'b'ตั้งค่าสถานะเมื่อต้องทำงานกับไฟล์ไบนารีบน DOS / Windows เท่านั้น (เนื่องจากไบนารีเป็นค่าเริ่มต้น POSIX) เป็นเรื่องดีที่มีวัตถุประสงค์สองอย่างเมื่อใช้ioใน 3.x เพื่อการเข้าถึงไฟล์
wescpy

208

คุณสามารถเข้ารหัสสตริงของคุณโดยใช้ .encode()

ตัวอย่าง:

'Hello World'.encode()

48

เช่นเดียวกับที่ได้รับการกล่าวถึงแล้วคุณกำลังอ่านไฟล์ในโหมดไบนารีแล้วสร้างรายการของไบต์ ในต่อไปนี้ของคุณสำหรับห่วงคุณกำลังเปรียบเทียบสตริงไบต์และที่เป็นที่รหัสเป็นความล้มเหลว

การถอดรหัสไบต์ขณะเพิ่มลงในรายการควรใช้งานได้ รหัสที่เปลี่ยนแปลงควรมีลักษณะดังนี้:

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

ชนิดไบต์ถูกนำมาใช้ใน Python 3 และนั่นคือสาเหตุที่รหัสของคุณทำงานใน Python 2 ใน Python 2 ไม่มีชนิดข้อมูลสำหรับไบต์:

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

25

คุณต้องเปลี่ยนจาก wb เป็น w:

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

ถึง

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

หลังจากเปลี่ยนสิ่งนี้ข้อผิดพลาดจะหายไป แต่คุณไม่สามารถเขียนไฟล์ (ในกรณีของฉัน) ดังนั้นหลังจากทั้งหมดฉันไม่มีคำตอบ?

ที่มา: วิธีลบ ^ M

การเปลี่ยนเป็น 'rb' ทำให้ฉันมีข้อผิดพลาดอื่น ๆ : io.UnsupportedOperation: write


15

สำหรับตัวอย่างเล็ก ๆ นี้: ซ็อกเก็ตนำเข้า

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

การเพิ่ม "b" ก่อน 'GET http://www.py4inf.com/code/romeo.txt HTTP / 1.0 \ n \ n' แก้ไขปัญหาของฉัน


11

ใช้ฟังก์ชัน encode () พร้อมกับค่าสตริง hardcoded ที่กำหนดในเครื่องหมายคำพูดเดี่ยว

Ex:

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

หรือ

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

8

คุณเปิดไฟล์ในโหมดไบนารี:

รหัสต่อไปนี้จะโยน TypeError: จำเป็นต้องมีวัตถุคล้ายไบต์ไม่ใช่ 'str'

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

รหัสต่อไปนี้ใช้ได้ - คุณต้องใช้ฟังก์ชั่นถอดรหัส ():

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

4

ทำไมไม่ลองเปิดไฟล์เป็นข้อความล่ะ?

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

นอกจากนี้ที่นี่ยังมีลิงค์สำหรับ python 3.x ในหน้าอย่างเป็นทางการ: https://docs.python.org/3/library/io.html และนี่คือฟังก์ชั่นเปิด: https://docs.python.org/3 /library/functions.html#open

หากคุณกำลังพยายามที่จะจัดการมันเป็นไบนารีแล้วให้พิจารณาการเข้ารหัสสตริงของคุณ


1

ฉันได้รับข้อผิดพลาดนี้เมื่อฉันพยายามแปลงถ่าน (หรือสตริง) bytesเป็นรหัสคือสิ่งนี้ด้วย Python 2.7:

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

นี่คือวิธีการของPython 2.7เมื่อจัดการกับตัวอักษร unicode

สิ่งนี้จะไม่ทำงานกับ Python 3.6 เนื่องจากbytesต้องการอาร์กิวเมนต์เพิ่มเติมสำหรับการเข้ารหัส แต่อาจยุ่งยากเล็กน้อยเนื่องจากการเข้ารหัสที่ต่างกันอาจให้ผลลัพธ์ที่ต่างกัน:

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

ในกรณีของฉันฉันต้องใช้iso_8859_1เมื่อเข้ารหัสไบต์เพื่อแก้ไขปัญหา

หวังว่านี่จะช่วยใครซักคน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.