TypeError:需要类似字节的对象,而在Python3中写入文件时不是'str'


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
为什么要以二进制模式打开文件却将其视为文本?
马丁·彼得斯

4
@MartijnPieters感谢您发现文件打开模式!将其更改为文本模式解决了该问题……尽管该代码在Py2k中可靠地工作了很多年……
masroore 2015年


10
我也有遇到这个问题,我有一个请求result = requests.get,我试图x = result.content.split("\n")。错误消息让我有些困惑,因为它似乎暗示这result.content是一个字符串,.split()并且需要一个类似字节的对象。(“需要一个类似字节的对象,而不是'str“')

Answers:


553

您以二进制模式打开文件:

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

这意味着从文件读取的所有数据都作为bytes对象而不是作为对象返回str。然后,您不能在收容测试中使用字符串:

if 'some-pattern' in tmp: continue

您必须改为使用一个bytes对象进行测试tmp

if b'some-pattern' in tmp: continue

或以文本文件形式打开文件,而不是将'rb'模式替换为'r'


12
如果您查看ppl链接到的各种文档,您会发现Py2中的所有内容都“起作用”,因为默认字符串是字节,而在Py3中,默认字符串是Unicode,这意味着您每次执行I / O时,尤其是 在网络上,字节字符串是标准配置,因此您必须学习移动黑白Unicode和字节字符串(en / decode)。对于文件,我们现在有了“ r”和“ rb”(以及“ w”和“ a”)来帮助区分。
wescpy

3
@wescpy:Python之2具有'r'VS 'rb' ,二进制和文本文件的行为之间的切换(例如平移换行和在某些平台上,所述EOF标记是如何处理的)。现在,该io库(在Python 3中提供了默认的I / O功能,但在Python 2中也提供了该功能)现在默认解码文本文件才是真正的改变。
马丁·彼得斯

2
@MartijnPieters:是的,同意。在2.x中,仅'b'当必须在DOS / Windows上处理二进制文件时才使用该标志(因为二进制文件是POSIX的默认设置)。io在3.x中使用文件访问有两个目的,这是很好的。
wescpy

207

您可以使用以下方式对字符串进行编码 .encode()

例:

'Hello World'.encode()

48

就像已经提到的一样,您正在以二进制模式读取文件,然后创建字节列表。在下面的for循环中,您将字符串与字节进行比较,这就是代码失败的地方。

在将字节添加到列表时对字节进行解码应该可以。更改后的代码应如下所示:

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:写入


15

对于这个小例子: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()

在'GET http://www.py4inf.com/code/romeo.txt HTTP / 1.0 \ n \ n' 之前添加“ b” 解决了我的问题


11

与单引号中给出的硬编码字符串值一起使用encode()函数。

例如:

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

以下代码将起作用-您必须使用encode()函数:

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


1

当我尝试将char(或字符串)转换为时,出现此错误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在对字节进行编码时来解决问题。

希望这对某人有帮助。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.