python 2 到 3 迁移失败主因是 str/bytes 混用、print 语句变函数引发 ast 兼容问题,以及第三方库版本不匹配;需显式处理编码、升级依赖并改用 logging 替代 print 调试。

Python 2 到 3 的 str / bytes 混用导致迁移失败
字符串在 Python 2 里是字节序列,默认 str 可直接写入文件或发 HTTP;Python 3 里 str 是 Unicode 文本,bytes 才是二进制数据。迁移时常见错误是把 Python 2 的 str 直接当文本处理,结果抛出 UnicodeDecodeError 或乱码。
- 读文件时别默认用
open('x.txt').read(),Python 3 下可能报错;显式指定编码:open('x.txt', encoding='utf-8').read() - 网络请求返回的响应体(如
requests.get(...).content)是bytes,不能直接.split('\n');要先解码:.content.decode('utf-8').split('\n') - 数据库驱动(如
psycopg2、mysql-connector-python)在 Python 3 下对参数类型更敏感:传bytes给期望str的字段会报TypeError
print 语句变成函数后引发的调用链断裂
Python 2 的 print 是语句,可直接 print x, y;Python 3 中是函数,必须加括号。表面看只是语法调整,但实际常因第三方库或自定义装饰器依赖 print 的 AST 结构而崩溃。
- 检查项目中是否用了
ast解析源码的工具(如代码覆盖率、日志注入),它们可能硬编码了Print节点类型,需升级到支持 Python 3 AST 的版本 -
from __future__ import print_function只影响当前文件,无法“透传”到被导入的旧模块;别指望加这一行就能让整个包兼容 - 调试时习惯性写的
print 'debug:', var在 Python 3 下直接 SyntaxError;建议用logging.debug('%r', var)替代,一劳永逸
第三方库版本不匹配引发的隐性兼容问题
不是所有库都同步支持 Python 3.8+,尤其是一些维护停滞的旧包(如 python-memcached 早期版、pyyaml 5.1 之前)。问题往往不报错,而是行为异常:比如 yaml.load() 默认不安全、memcache.set() 静默丢弃非字符串值。
PHP经典实例(第2版)能够为您节省宝贵的Web开发时间。有了这些针对真实问题的解决方案放在手边,大多数编程难题都会迎刃而解。《PHP经典实例(第2版)》将PHP的特性与经典实例丛书的独特形式组合到一起,足以帮您成功地构建跨浏览器的Web应用程序。在这个修订版中,您可以更加方便地找到各种编程问题的解决方案,《PHP经典实例(第2版)》中内容涵盖了:表单处理;Session管理;数据库交互;使用We
- 运行
pip list --outdated后,重点查django、celery、sqlalchemy这类核心依赖的 Python 3 兼容说明,它们的文档里通常有明确的Requires-Python标注 - 避免用
pip install package==latest,latest不代表兼容当前 Python 版本;改用pip install "package>=X.Y,<z.0> 并参考其 <code>setup.py中的python_requires - CI 流程里加一条
python -c "import package; print(package.__version__)",防止安装了错误轮子(wheel)导致本地能跑、CI 报错
路径和文件系统操作中的编码陷阱
Python 2 对文件名基本不做编码校验,Linux 下用中文路径可能侥幸通过;Python 3 在 os.listdir()、pathlib.Path.iterdir() 等操作中会严格按系统 locale 解码,遇到无法识别的字节序列就抛 UnicodeDecodeError。
立即学习“Python免费学习笔记(深入)”;
- 不要依赖
sys.getdefaultencoding()—— 它通常是'utf-8',但不影响文件系统 API 的行为;真正起作用的是locale.getpreferredencoding() - 处理不确定编码的路径时,用
os.fsencode()/os.fsdecode()而非手动.encode('utf-8'),它们会适配当前平台的实际行为 -
pathlib.Path在 Python 3.6+ 支持Path(b'/path/with/bytes')构造,但很多方法(如.glob())仍要求 Unicode 字符串;遇到模糊路径,优先用os.scandir()+entry.name(返回str或bytes视情况而定)









