Python 3 严格区分 str(文本)和 bytes(二进制),二者类型、内存表示及操作接口均不同,混用导致 TypeError 或 UnicodeDecodeError;必须用 .encode() 和 .decode() 显式转换,且编码名需准确匹配。

bytes 和 str 在 Python 里不是能自动互转的“同一种东西”
Python 3 强制区分文本(str)和二进制数据(bytes),它们类型不同、内存表示不同、操作接口也不同。试图直接拼接、比较或传参时出错,比如 TypeError: can't concat bytes to str 或 UnicodeDecodeError,根本原因就是混用了这两类对象。
关键判断:只要涉及文件读写、网络传输、编码处理、加密哈希等场景,就必须明确当前变量是 str 还是 bytes,不能靠“看起来像字符串”来猜测。
什么时候必须用 .encode() 和 .decode()
.encode() 把 str 变成 bytes,.decode() 把 bytes 变回 str。这不是可选项,是类型转换的唯一合法方式。漏掉、反向调用、或编码名不匹配,都会立刻报错。
- 读文件时用
open(..., 'r', encoding='utf-8')→ 返回str;用open(..., 'rb')→ 返回bytes,此时不能直接 .split('\n'),得先.decode('utf-8') - HTTP 响应体(如
requests.get(...).content)是bytes,要转文本必须显式.decode('utf-8')(注意:不是所有响应都声明了编码,别硬写response.text就以为安全) -
subprocess.run(..., stdout=subprocess.PIPE)的stdout是bytes,打印前要么 decode,要么用text=True参数让 subprocess 自动处理 - 错误信息里出现
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0,说明你拿utf-8去解码一个其实是gbk或带 BOM 的bytes,得换编码重试
常见坑:encode/decode 的参数不是摆设
编码名写错、省略、或依赖默认值,是隐形雷区。Python 默认编码是 utf-8,但很多老系统、Windows 文件、Excel 导出 CSV 默认用 gbk 或 cp1252。不指定或写错,程序可能在一台机器跑通,换一台就崩。
Perl学习手札是台湾perl高手写的一篇文章,特打包为chm版,方便大家阅读。 关于本书 1. 关于Perl 1.1 Perl的历史 1.2 Perl的概念 1.3 特色 1.4 使用Perl的环境 1.5 开始使用 Perl 1.6 你的第一个Perl程序 2. 标量变量(Scalar) 2.1 关于标量 2.1.1 数值 2.1.2 字符串 2.1.3 数字与字符串转换 2.2 使用你自己的变量 2.3 赋值 2.3.1 直接设定 2.3.2 还可以这样 2.4 运算 2.5 变量的输出/输入 2.
立即学习“Python免费学习笔记(深入)”;
-
'中文'.encode()等价于'中文'.encode('utf-8'),没问题;但b'\xc4\xe3'.decode()会按utf-8解,实际是gbk编码,就报错 - 用
open(..., 'w')写str时,encoding 不写等于用系统默认,Linux 是utf-8,Windows 控制台可能是cp936,结果文件在别处打不开 - 网络协议(如 HTTP header、JSON RPC)通常要求 ASCII-only 的
bytes,传中文str过去会直接失败,得先 encode 成utf-8再构造成 header 字段
len()、切片、in 操作的行为差异
对 str 和 bytes 同样写 len(s) 或 s[0:3],结果完全不同:前者按 Unicode 字符数算,后者按字节数算。这个差异在截断、分块、协议解析时极易出错。
-
len('€')是 1(一个字符),len('€'.encode('utf-8'))是 3(UTF-8 下欧元符号占 3 字节) -
b'abc\xff'[0:2]返回b'ab';'café'[0:2]返回'ca';但'café'.encode()[0:2]是b'ca',而'café'.encode()[0:3]是b'caf'—— 因为 é 在 UTF-8 中是 2 字节,开头 3 字节刚好卡在中间,decode 会失败 -
b'hello' in b'hello world'是 True;'hello' in b'hello world'是 False(类型不匹配,直接报错)
真正麻烦的是那些“看起来能过,其实逻辑错”的地方:比如按字节长度切日志行、用 bytes.find() 找 ASCII 关键字、却忘了输入可能是带 emoji 的 str —— 这类问题不会立刻报错,但数据会被截断或错位。









