Python 2 到 3 迁移
问题
如何将 Python 2 项目迁移到 Python 3?有哪些常见的兼容性问题?
答案
迁移策略
核心差异
| 特性 | Python 2 | Python 3 |
|---|---|---|
print "hello" | print("hello") | |
| 除法 | 3/2 = 1 | 3/2 = 1.5 |
| 字符串 | str 是字节 | str 是 Unicode |
| range | 返回 list | 返回迭代器 |
| dict.keys() | 返回 list | 返回 view |
| 异常 | except E, e: | except E as e: |
| input | raw_input() | input() |
迁移工具
# 1. 使用 2to3 自动转换
2to3 -w myproject/ # -w 直接写入文件
# 2. 使用 futurize(更保守)
pip install future
futurize --stage1 -w myproject/ # 第一阶段:安全修改
futurize --stage2 -w myproject/ # 第二阶段:Python 3 特性
# 3. 使用 pyupgrade(现代化代码)
pip install pyupgrade
pyupgrade --py3-plus myproject/**/*.py
常见修改
migration/common_fixes.py
# 1. print 语句 → 函数
# ❌ Python 2
# print "hello", name
# ✅ Python 3
print("hello", name)
# 2. 除法
# ❌ Python 2: 3/2 = 1
# ✅ Python 3: 3/2 = 1.5, 3//2 = 1
from __future__ import division # 兼容层
# 3. 字符串 / 字节
# ❌ Python 2: str 和 unicode 混用
# ✅ Python 3: str 是 Unicode,bytes 是字节
text: str = "你好"
data: bytes = b"hello"
encoded = text.encode("utf-8")
decoded = data.decode("utf-8")
# 4. 字典方法
# ❌ Python 2
# d.keys() → list
# d.iteritems() → iterator
# ✅ Python 3
d.keys() # → view 对象
d.items() # → view 对象(没有 iteritems)
list(d.keys()) # 需要 list 时显式转换
# 5. 异常
# ❌ Python 2
# except ValueError, e:
# raise ValueError, "message"
# ✅ Python 3
try:
...
except ValueError as e:
raise ValueError("message") from e
# 6. 类定义
# ❌ Python 2
# class MyClass(object): # 需显式继承 object
# ✅ Python 3
class MyClass: # 默认继承 object
pass
# 7. super()
# ❌ Python 2
# super(MyClass, self).__init__()
# ✅ Python 3
super().__init__()
# 8. 类型注解(Python 3 独有)
def greet(name: str) -> str:
return f"Hello, {name}"
兼容层(渐进迁移)
compat.py
"""兼容 Python 2 和 3 的过渡模块"""
import sys
PY2 = sys.version_info[0] == 2
if PY2:
string_types = (str, unicode)
text_type = unicode
binary_type = str
range = xrange
else:
string_types = (str,)
text_type = str
binary_type = bytes
range = range
常见面试问题
Q1: 迁移中最大的坑?
答案:
- 字符串编码:Python 2 的 str/unicode 混用导致大量
UnicodeDecodeError - 第三方库:部分库不支持 Python 3
- 隐式行为变化:
/除法、dict.keys()返回类型变了 - 测试覆盖不足:没测到的代码迁移后才发现问题
Q2: 如何保证迁移不出问题?
答案:
- 先加测试:迁移前提高测试覆盖率到 80%+
- 逐步迁移:一个模块一个模块改
- CI 双版本:同时在 Python 2 和 3 跑测试
- 灰度切换:先在预发环境验证
Q3: Python 2 已停止维护,为什么还要了解?
答案:
- 很多公司仍有历史遗留的 Python 2 代码
- 面试考察迁移能力和对语言演进的理解
- 理解 Python 3 特性的来龙去脉