Python 2 与 Python 3 的主要区别详解
随着 Python 2 于 2020 年正式停止维护,开发者应全面转向 Python 3。尽管两者核心语法相似,但在性能、编码、语法特性及标准库等方面存在显著差异。本文详细梳理了主要区别,帮助开发者快速理解并迁移。
1. 性能
Python 3 在早期版本(如 Py3.0)运行 pystone benchmark 的速度比 Py2.5 慢约 30%。Guido van Rossum 认为 Py3.0 有极大的优化空间,特别是在字符串和整数操作上。后续版本(如 Py3.1)性能提升至比 Py2.5 慢 15% 左右。现代 Python 3 版本经过大量优化,性能已大幅提升,甚至在某些场景下优于旧版 Python 2。
2. 编码
- Python 2:源码文件默认使用 ASCII 编码,处理非 ASCII 字符需显式声明
# -*- coding: utf-8 -*-。 - Python 3:源码文件默认使用 UTF-8 编码,无需额外声明即可直接处理中文等 Unicode 字符。
3. 语法差异
3.1 运算符与关键字
- 比较运算符:去除了
<>,全部改用!=。 - 字符串表示:去除了反引号
`,统一改用repr()函数。 - 关键字:加入了
as和with;True、False、None变为关键字而非变量。 - 整型除法:
- Py2:
1 / 2结果为0(整除)。 - Py3:
1 / 2结果为0.5(浮点)。若需整除,请使用//。
- Py2:
- Nonlocal 语句:新增
nonlocal语句,用于指派外围(非全局)变量。 - Print 与 Exec:
- Py2:
print是语句,exec是语句。 - Py3:
print()是函数,exec()是函数。
- Py2:
- 顺序操作符:例如
x < y,当x和y类型不匹配时抛出TypeError,而不是返回随机布尔值。 - 输入函数:
- Py2:使用
raw_input()读取键盘输入。 - Py3:使用
input()代替raw_input()。
# Py2 guess = int(raw_input('Enter an integer : ')) # Py3 guess = int(input('Enter an integer : ')) - Py2:使用
- 元组参数解包:Py3 中不能像 Py2 那样定义函数
def(a, (b, c)): pass,需使用更明确的解包方式。 - 字面量:
- 新式的 8 进制字面量,修改了
oct()函数行为。 - 增加了 2 进制字面量和
bin()函数。
- 新式的 8 进制字面量,修改了
- 可迭代解包:支持扩展的可迭代解包,如
a, b, *rest = seq和*rest, a = seq,要求rest是列表且对象可迭代。 - Super():新的
super()可以不再传参数,简化继承调用。 - Metaclass 语法:
class Meta(type): pass class Foo(metaclass=Meta): pass - Class Decorator:支持类装饰器,用法与函数装饰器类似。
4. 字符串和字节串
- 字符串类型:现在只有
str一种类型,对应 Py2 的unicode。 - 字节串:新增了
bytes类型,对应 Py2 的八位串。- 定义方法:
b = b'hello' - 转换:
str对象和bytes对象可以使用.encode()(str -> bytes) 或.decode()(bytes -> str) 相互转化。
- 定义方法:
5. 数据类型
- 整型:Py3 去除了
long类型,现在只有一种整型int,其行为类似于 Py2 的long。 - 字典视图:
.keys()、.items()和.values()方法返回迭代器,之前的iterkeys()等函数被废弃。同时去掉了dict.has_key(),改用in替代。if 'key' in my_dict: print(my_dict['key'])
6. 面向对象
- 抽象基类 (ABCs):引入抽象基类,容器类和迭代器类被 ABCs 化。
- 迭代器协议:迭代器的
next()方法改名为__next__(),并增加内置函数next()用以调用。 - 装饰器:增加了
@abstractmethod和@abstractproperty两个装饰器,编写抽象方法更方便。
7. 异常处理
- 继承关系:所有异常都从
BaseException继承,删除了StandardError。 - 属性移除:去除了异常类的序列行为和
.message属性。 - Raise 语法:用
raise Exception(args)代替raise Exception, args语法。 - 捕获语法:引入了
as关键字来标识异常实例。try: x = 1 / 0 except ZeroDivisionError as e: print(e) - 异常链:支持异常链,通过
__context__追踪上下文。
8. 模块变动
- Pickle:移除了
cPickle模块,直接使用pickle模块。 - 移除模块:移除了
imageop,audiodev,bsddb185,exceptions,linuxaudiodev,md5,MimeWriter,mimify,popen2,rexec,sets,sha,stringold,strop,sunaudiodev,timing,xmllib等模块。 - Bsddb:移除了
bsddb模块(单独发布)。 - New 模块:移除了
new模块。 - 临时文件:
os.tmpnam()和os.tmpfile()函数被移动到tempfile模块下。 - Tokenize:
tokenize模块现在使用bytes工作,入口点改为tokenize.tokenize()。
9. 其他重要变更
- Range:
xrange()改名为range()。若要获得列表,需显式调用list()。>>> list(range(10)) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - Bytes 对象:
bytes对象不能 hash,也不支持b.lower()、b.strip()和b.split()方法,但可通过指定字节参数实现类似功能。 - 函数移除:
zip()、map()和filter()都返回迭代器。而apply()、callable()、coerce()、execfile()、reduce()和reload()函数被去除。可使用hasattr()替换callable()。 - String 常量:
string.letters及相关.lowercase和.uppercase被去除,请改用string.ascii_letters等。 - 比较行为:如果
x < y不能比较,抛出TypeError异常。Py2 版本是返回伪随机布尔值的。 - 切片成员:
__getslice__系列成员被废弃。a[i:j]根据上下文转换为a.__getitem__(slice(i, j))或__setitem__和__delitem__调用。 - File 类:
file类被废弃,统一使用open()返回的文件对象。
10. 迁移建议
由于 Python 2 已停止官方支持,新项目应强制使用 Python 3。对于遗留项目,建议使用 2to3 工具进行自动转换,并手动修复兼容性问题。重点检查以下方面:
- 字符串与字节串的混合使用。
- 除法运算的预期结果。
- 异常捕获语法的更新。
- 第三方库的 Python 3 兼容性。
通过遵循上述指南,开发者可以更平稳地完成从 Python 2 到 Python 3 的过渡,享受新版本带来的安全性与性能提升。

