Python 2.x 与 3.x 核心差异详解
本文详细解析了 Python 2.x 与 3.x 版本之间的核心差异。重点涵盖 print 语句向函数的转变、Unicode 编码处理的改进、除法运算规则的调整、异常处理机制的规范化,以及 xrange 与 range 的合并。此外,还介绍了八进制字面量、不等运算符、模块重命名及数据类型(如 bytes 和 int)的变化,帮助开发者理解版本迭代带来的语法变更。
Python 3.0 升级背景与兼容性说明
Python 3.0 版本,常被通俗地称为 Python 3000 或简写为 Py3k。相较于早期版本,这是一次具有重大意义的升级迭代。
为了保持语言设计的简洁性并避免引入过多的历史包袱,Python 3.0 在设计之初并未考虑向下兼容。
因此,许多为早期 Python 版本编写的程序无法直接在 Python 3.0 环境中正常运行。
为了兼顾现有代码库的平滑过渡,Python 2.6 被设计为一个过渡版本。它基本沿用了 Python 2.x 的语法和库,同时引入了对 Python 3.0 部分语法和函数的支持,以便开发者逐步迁移。
对于新开发的 Python 程序,官方建议使用 Python 3.0 版本的语法进行编写。
仅在两种情况下可例外:一是执行环境无法安装 Python 3.0;二是程序依赖的第三方库不支持 Python 3.0。目前,部分第三方库如 Twisted、py2exe 和 PIL 等尚未完全支持 Python 3.0。
大多数第三方库正在积极努力兼容 Python 3.0 版本。即使当前环境暂时无法使用 Python 3.0,也建议编写兼容 Python 3.0 的代码,并可使用 Python 2.6 或 Python 2.7 进行执行测试。
Python 2.x 与 3.x 核心差异详解
Python 3.0 的主要变化体现在以下几个方面:
print 语句与函数
print 函数
在 Python 3 中,print 语句已被移除,取而代之的是 print() 函数。Python 2.6 和 Python 2.7 部分支持这种新的 print 语法。在 Python 2.6 与 Python 2.7 中,以下三种写法是等价的:
print "fish"
print ("fish") #注意print后面有个空格
print("fish") #print()不能带有任何其它参数
然而,Python 2.6 实际上已经支持新的 print() 语法:
from __future__ import print_function
print("fish", "panda", sep=', ')
Unicode 编码处理
Unicode
在 Python 2 中,str() 类型对应 ASCII 编码,而 unicode() 是单独的类型,并非字节类型。
在 Python 3 中,我们最终拥有了基于 Unicode (UTF-8) 的字符串类型,以及专门的字节类:bytes 和 bytearray。
由于 Python 3.x 的源码文件默认使用 UTF-8 编码,因此以下代码是合法的:
>>> 中国 = 'china'
>>>print(中国)
china
Python 2.x
>>> str = "我爱北京天安门"
>>> str
'\xe6\x88\x91\xe7\x88\xb1\xe5\x8c\x97\xe4\xba\xac\xe5\xa4\xa9\xe5\xae\x89\xe9\x97\xa8'
>>> str = u"我爱北京天安门"
>>> str
u'\u6211\u7231\u5317\u4eac\u5929\u5b89\u95e8'
Python 3.x
>>> str = "我爱北京天安门"
>>> str
'我爱北京天安门'
除法运算规则变化
除法运算
Python 中的除法运算规则相较于其他编程语言更为复杂,涉及两个运算符:/ 和 //。
首先来看 / 除法:
在 Python 2.x 中,/ 除法的行为与 Java、C 等语言类似:整数相除的结果为整数,小数部分被直接忽略;而浮点数相除则会保留小数部分,返回浮点数结果。
在 Python 3.x 中,/ 除法的行为发生了变化:即使是整数之间的相除,结果也会是浮点数。
Python 2.x:
>>> 1 / 2
0
>>> 1.0 / 2.0
0.5
Python 3.x:
>>> 1/2
0.5
对于 // 除法,这被称为 floor 除法(向下取整除法),它会对除法结果自动执行 floor 操作。在 Python 2.x 和 Python 3.x 中,这一行为是一致的。
python 2.x:
>>> -1 // 2
-1
python 3.x:
>>> -1 // 2
-1
需要注意的是,// 并非简单地舍弃小数部分,而是执行 floor 操作。如果需要截取整数部分(向零取整),应使用 math 模块中的 trunc 函数。
python 3.x:
>>> import math
>>> math.trunc(1 / 2)
0
>>> math.trunc(-1 / 2)
0
异常处理机制改进
异常处理
在 Python 3 中,异常处理的语法发生了细微变化。现在统一使用 as 作为关键字。
捕获异常的语法由旧的 except exc, var 改为 except exc as var。
使用语法 except (exc1, exc2) as var 可以同时捕获多种类型的异常。Python 2.6 已经支持这两种语法。
- 1. 在 Python 2.x 时代,所有类型的对象都可以被直接抛出;而在 Python 3.x 中,只有继承自 BaseException 的对象才可以被抛出。
- 2. Python 2.x 的 raise 语句使用逗号将抛出对象的类型和参数分开,而 Python 3.x 取消了这种写法,改为直接调用构造函数来抛出对象。
在 Python 2.x 时代,异常在代码中除了表示程序错误外,还常被用于执行普通控制结构应做的事情。而在 Python 3.x 中,设计者使异常处理更加专一,仅在发生错误时才使用异常捕获语句进行处理。
xrange 与 range 的合并
xrange
在 Python 2 中,xrange() 创建迭代对象的用法非常流行,例如用于 for 循环或列表/集合/字典推导式。
这种行为类似于生成器(即“惰性求值”)。但 xrange 迭代器是无限的,意味着你可以无限遍历它。
由于其惰性求值的特性,如果你只需要遍历一次,xrange() 函数比 range() 更快(例如在 for 循环中)。尽管如此,不建议重复迭代多次,因为生成器每次都会从头开始。
在 Python 3 中,range() 的实现方式类似于 Python 2 中的 xrange(),因此专门的 xrange() 函数已不再存在(在 Python 3 中调用 xrange() 会抛出 NameError)。
import timeit
n = 10000
def test_range(n):
return for i in range(n):
pass
def test_xrange(n):
for i in xrange(n):
pass
Python 2
print 'Python', python_version()
print '\ntiming range()'
%timeit test_range(n)
print '\n\ntiming xrange()'
%timeit test_xrange(n)
Python 2.7.6
timing range()
1000 loops, best of 3: 433 µs per loop
timing xrange()
1000 loops, best of 3: 350 µs per loop
Python 3
print('Python', python_version())
print('\ntiming range()')
%timeit test_range(n)
Python 3.4.1
timing range()
1000 loops, best of 3: 520 µs per loop
print(xrange(10))
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-5-5d8f9b79ea70> in <module>()
----> 1 print(xrange(10))
NameError: name 'xrange' is not defined
八进制与二进制字面量
八进制字面量表示
八进制数必须写成 0o777 的形式,原来的写法 0777 已不再允许;二进制必须写成 0b111。
新增了一个 bin() 函数,用于将整数转换为二进制字符串。Python 2.6 已经支持这两种语法。
在 Python 3.x 中,表示八进制字面量的方式只有一种,即 0o1000。
python 2.x
>>> 0o1000
512
>>> 01000
512
python 3.x
>>> 01000
File "<stdin>", line 1
01000
^
SyntaxError: invalid token
>>> 0o1000
512
不等运算符与 repr 表达式
不等运算符
在 Python 2.x 中,不等于有两种写法:!= 和 <>。
在 Python 3.x 中,<> 被移除,只保留 != 一种写法。幸运的是,<> 的使用习惯并不普遍。
去掉了 repr 表达式 ``
在 Python 2.x 中,反引号 `` 相当于 repr() 函数的作用。
在 Python 3.x 中,去掉了 `` 这种写法,只允许使用 repr() 函数。这样做的目的是使代码更加清晰。不过,repr() 的使用频率通常较低,多用于调试,多数时候仍使用 str() 函数来描述对象。
def sendMail(from_: str, to: str, title: str, body: str) -> bool: pass
模块重命名与合并
多个模块被改名(根据 PEP8 规范)
| 旧的名字 | 新的名字 |
| _winreg | winreg |
| ConfigParser | configparser |
| copy_reg | copyreg |
| Queue | queue |
| SocketServer | socketserver |
| repr | reprlib |
StringIO 模块现在被合并到新的 io 模块内。new、md5、gopherlib 等模块已被删除。Python 2.6 已经支持新的 io 模块。
httplib、BaseHTTPServer、CGIHTTPServer、SimpleHTTPServer、Cookie、cookielib 被合并到 http 包内。
取消了 exec 语句,只剩下 exec() 函数。Python 2.6 已经支持 exec() 函数。
数据类型变更
数据类型
- Python 3.x 去除了 long 类型,现在只有一种整型——int,但其行为类似于 Python 2.x 中的 long。
- 新增了 bytes 类型,对应于 Python 2.x 中的八位串。定义一个 bytes 字面量的方法如下:
>>> b = b'china'
>>> type(b)
<type 'bytes'>
str 对象和 bytes 对象可以使用 .encode() (str -> bytes) 或 .decode() (bytes -> str) 方法相互转化。
>>> s = b.decode()
>>> s
'china'
>>> b1 = s.encode()
>>> b1
b'china'
- dict 的 .keys()、.items() 和 .values() 方法返回迭代器,而之前的 iterkeys() 等函数已被废弃。同时去掉了 dict.has_key(),请使用 in 关键字替代它。
以上就是 Python 2.x 与 3.x 版本区别的详细总结,更多关于 Python 2.x 与 3.x 区别的资料请关注本站其他相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









