python 2的str是字节序列,python 3的str是unicode字符串,这是编码错误的根源;读写文件须显式指定encoding="utf-8",避免依赖默认locale;终端、网络、数据库各层编码需单独校验并保持一致。

Python 2 和 Python 3 的 str 类型本质不同
Python 2 的 str 是字节序列,Python 3 的 str 是 Unicode 字符串——这是绝大多数编码错误的起点。不是“没设编码”,而是你默认在拿 Python 3 当 Python 2 用。
常见错误现象:UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe4 in position 0,或中文显示成 \xe4\xbd\xa0\xe5\xa5\xbd。
- 读文件时没指定
encoding参数(Python 3 默认用系统 locale,Windows 常是cp936,Linux 常是utf-8) - 用
str(byte_string)强转字节对象(Python 3 中这会调用__str__,不是解码) - 混用
bytes和str做拼接,比如b"hello" + "world"
open() 不加 encoding 就等于开盲盒
Python 3 的 open() 默认使用 locale.getpreferredencoding(),它不等于文件实际编码,也不等于你编辑器保存的编码。
使用场景:读写配置、日志、用户提交的文本文件。
立即学习“Python免费学习笔记(深入)”;
- 明确写死
encoding="utf-8",除非你确定文件是 GBK(如 Windows 记事本旧版保存) - 写文件时也必须加
encoding,否则print(..., file=f)可能因默认编码不匹配而报错 - 遇到乱码先用
chardet.detect()猜编码,但别依赖它自动解码——它只是启发式估算
示例:with open("data.txt", encoding="utf-8") as f: content = f.read()
sys.stdout.encoding 和终端实际支持的编码经常对不上
Python 启动时会从环境推断 sys.stdout.encoding,但 Windows CMD、PowerShell、IDE 内置终端、SSH 连接各自有一套编码逻辑,print() 出来的是什么,取决于三者是否一致:Python 推断出的编码、终端当前代码页、字符串本身是否已正确解码。
常见错误现象:脚本里 print("你好") 在 PyCharm 正常,在 CMD 报错;或者输出是问号或方块。
- Windows 上 CMD 默认是
cp936,但 Python 可能设成utf-8,这时需手动改终端:执行chcp 65001 - 不要用
sys.setdefaultencoding()—— 它只在启动初期有效,且强行修改会掩盖真实问题 - 如果必须兼容老旧终端,把输出先 encode 成目标编码再 write 到
sys.stdout.buffer
HTTP 响应、JSON、数据库字段的编码要单独校验
网络和存储层不认 Python 的字符串抽象,它们只认字节流。你以为传的是字符串,其实中间已经过一次隐式编码/解码。
使用场景:调用 API、存 MySQL、解析 JSON 返回体。
-
requests.get().text依赖响应头的charset,若缺失或错误,结果就是乱码;更稳的方式是用.content.decode("utf-8")显式控制 - MySQL 的
CHARSET=utf8mb4和连接参数charset="utf8mb4"必须同时设置,缺一不可 - JSON 只接受 Unicode 字符串,
json.loads()输入必须是str,不能是bytes;而json.dumps()输出默认是str,想得字节要用ensure_ascii=False+.encode()
create_engine 没传 charset,或者 Nginx 反向代理时加了错误的 charset 头。查的时候得一层层确认字节进来时是谁解的码。










