ChatGPT解决这个技术问题 Extra ChatGPT

TypeError:在 Python 3 中写入文件时需要一个类似字节的对象,而不是“str”

我最近迁移到 Python 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:需要一个类似字节的对象,而不是“str”

错误在最后一行(模式搜索代码)。

我尝试在语句的任一侧使用 .decode() 函数,还尝试过:

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

- 无济于事。

我能够快速解决几乎所有 Python 2 到 Python 3 的问题,但是这个小声明让我很烦。

为什么以二进制模式打开文件但将其视为文本?
@MartijnPieters 感谢您发现文件打开模式!将其更改为文本模式解决了这个问题......尽管代码在 Py2k 中可靠地运行了很多年......
我也遇到了这个问题,我有一个请求 result = requests.get 并尝试 x = result.content.split("\n")。我对错误消息有点困惑,因为它似乎暗示 result.content 是一个字符串,而 .split() 需要一个类似字节的对象..?? (“需要一个类似字节的对象,而不是'str'')..
Martjin 是对的,您应该将 'rb' 选项更改为 'r' 以将文件视为字符串

M
Martijn Pieters

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

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' 来将文件作为文本文件打开。


如果您查看 ppl 链接到的各种文档,您会发现 Py2 中的所有内容都“正常工作”,因为默认字符串是字节,而在 Py3 中,默认字符串是 Unicode,这意味着任何时候进行 I/O,尤其是网络,字节字符串是标准,所以你必须学会移动黑白 Unicode 和字节字符串(en/decode)。对于文件,我们现在有“r”与“rb”(以及“w”和“a”)来帮助区分。
@wescpy:Python 2 有 'r' vs 'rb' too,在二进制文件和文本文件行为之间切换(比如翻译换行符和在某些平台上,EOF 标记的处理方式)。 io 库(在 Python 3 中提供默认 I/O 功能,但在 Python 2 中也可用)现在默认也解码文本文件是真正的变化。
@MartijnPieters:是的,同意。在 2.x 中,当必须在 DOS/Windows 上处理二进制文件时,我只使用了 'b' 标志(因为二进制是 POSIX 默认的)。在 3.x 中使用 io 进行文件访问时有双重用途,这很好。
@ericOnline ZipFile.open() docs explicitly state that only binary mode is supportedbinary 类文件对象的形式访问存档成员)。您可以将文件对象包装在 io.TextIOWrapper() 中以达到相同的效果。
@ericOnline 同样,当您可以直接迭代文件对象时,不要使用 .readlines() 。尤其是当您只需要来自单行的信息时。当可以在第一个缓冲块中找到该信息时,为什么要将所有内容读入内存?
T
Theofilos Papapanagiotou

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

例子:

'Hello World'.encode()

如错误所述,为了将字符串写入文件,您需要先将其编码为类似字节的对象,并且 encode() 将其编码为字节字符串。


此注释在使用 fd.subprocess.Popen(); fd.communicate(...); 的情况下非常有用。
如果之后需要连接到字符串(TypeError: can only concatenate str (not "bytes") to str):"Hello "+("World".encode()).decode()(显然与 join() 相同)。
为什么这行得通?
您不能将字符串写入文件,您需要将字符串编码为类似字节的对象才能这样做。通过运行字符串的 encode() 方法,我们可以得到默认编码的编码版本,通常是 utf-8
S
Suresh

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

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

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

bytes 类型是在 Python 3 中引入的,这就是您的代码在 Python 2 中工作的原因。在 Python 2 中,没有字节数据类型:

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

Python 2 确实有一种字节类型,只是混淆地称为 str 而文本字符串的类型称为 unicode。在 Python 3 中,他们更改了 str 的含义,使其与旧的 unicode 类型相同,并将旧的 str 重命名为 bytes。他们还删除了一堆它会自动尝试从一个转换到另一个的情况。
C
Community

您必须从 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'])

更改此设置后,错误消失,但您无法写入文件(在我的情况下)。所以毕竟,我没有答案?

来源:How to remove ^M

更改为“rb”给我带来了另一个错误:io.UnsupportedOperation: write


为什么这行得通? explanation 将是有序的。 (但没有“编辑:”、“更新:”或类似的 - 答案应该看起来好像是今天写的。)
F
Freddy Mcloughlan

对于这个小例子,在 'GET http://www.py4inf.com/code/romeo.txt HTTP/1.0\n\n' 之前添加唯一的 b 解决了我的问题:

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

字符串文字前面的“b”字符有什么作用?


为什么它有效? OP 已经离开了大楼(“最后一次出现在 5 年前”),所以也许其他人可以插话?
P
Peter Mortensen

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

例子:

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

或者

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

为什么这行得通?
M
Matan Hugi

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

以下代码将引发 TypeError:需要一个类似字节的对象,而不是 'str'。

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

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

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

P
Peter Mortensen

尝试以文本形式打开文件:

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

此外,这里是官方页面上 Python 3.x 的链接:io — Core tools for working with streams

这是开放函数:open

如果您真的想将其作为二进制文件处理,请考虑对您的字符串进行编码。


P
Peter Mortensen

当我尝试将字符(或字符串)转换为 bytes 时出现此错误,代码与 Python 2.7 类似:

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

这是处理 Unicode 字符时 Python 2.7 的方式。

这不适用于 Python 3.6,因为 bytes 需要一个额外的编码参数,但这可能有点棘手,因为不同的编码可能会输出不同的结果:

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

在我的情况下,我必须在编码字节时使用 iso_8859_1 才能解决问题。


请注意,文件顶部的 coding 注释不会影响 bytesencode 的工作方式,它只会更改 Python 源代码中字符的解释方式。

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅