Python 2.x 与 3.x 版本区别
本章节,我们将介绍一下 Python 3.X 和 Python2.X 之间的差别
首先,第一句话
新开发的项目,首先推荐你使用 Python3
Python 3.X 版本,简称 Py3k, 对于 Python 的早期版本,这是一个重大的不兼容的升级
为了不带入过多的累赘,Python 3.X 在设计的时候没有考虑向下相容
许多针对早期 Python 版本设计的程序和库都无法在 Python 3.0 上正常执行
为了照顾现有程序,Python 2.6-2.7 作为一个过渡版本,基本使用了 Python 2.x 的语法和库,同时考虑了向 Python 3.0 的迁移,允许使用部分 Python 3.X 的语法与函数
Python 3.X 的变化主要在以下几个方面
1. print()
Py3.X print 语句没有了,取而代之的是 print() 函数
Py2.X print 语句
>>> print "Hello", ' ', 'World' Hello World
Py3.X print() 函数
>>> print 'Hello', ' ', 'World' SyntaxError: Missing parentheses in call to 'print'. Did you mean print('Hello', ' ', 'World')? >>> print('Hello', ' ', 'World') Hello World
Python 2.6+ 使用 print() 函数
from __future__ import print_function >>> print('Hello', ' ', 'World') Hello World
2. Unicode
Python3.X 源码文件默认使用 utf-8 编码
这个应该算是 3.X 和 2.X 最大的差别了,意味着我们不用使用烦人的
# -*- encoding:utf-8 -*-
喜极而泣,奔走相告
Python2.X 有 ASCII str
类型,unicode()
是单独的,不是 byte
类型
Python3.X 中终有了 Unicode (utf-8)
字符串,以及一个字节类 byte 和 bytearrays
也就是说,下面的代码是合法的,再也不会报 SyntaxError: invalid syntax
错误了
>>> 简单教程 = 'jiandanjiaocheng.com' >>>print(简单教程) jiandanjiaocheng.com
Python 2.x 使用 Unicode
Python2.x 中要使用 Unicode 必须在字符串前加 u
字符
>>> s = "简单教程,简单编程" >>> s '\xe7\xae\x80\xe5\x8d\x95\xe6\x95\x99\xe7\xa8\x8b,\xe7\xae\x80\xe5\x8d\x95\xe7\xbc\x96\xe7\xa8\x8b' >>> s = u"简单教程,简单编程" >>> s u'\u7b80\u5355\u6559\u7a0b,\u7b80\u5355\u7f16\u7a0b'
Python 3.x
>>> s = "简单教程,简单编程" >>> s 简单教程,简单编程
3. /
除法运算
Python 中的除法有两个运算符,/
和 //
Py2.x 中 /
除法跟我们在数学中学习的一样
- 如果除数和被除数都是整数,相除的结果是一个整数,把小数部分完全忽略掉( 不是四舍五入)
- 如果只要其中之一是浮点数,那么除法会保留小数点的部分得到一个浮点数的结果
Py3.x 中 /
除法的实现就差别大了,无论两个数是否是整数,都返回浮点数的结果
Py2.x
>>> 4 / 2 2 >>> 4.0 / 2.0 2.0
Py3.x
不管除数和被除数是否都是整数,返回的结果一定是浮点数
>>> 4/2 2.0
4. 对于 //
除法
//
叫做 floor
除法,俗称 地板流除法
//
除法会对除法的结果自动进行一个 math.floor() 操作,也就是向下取整
//
除法在 Py2.X 和 Py3.X 中效果是一致的
Py2.X
>>> -5 // 2 -3
Py3.X
>>> -5 // 2 -3
//
除法是并不是舍弃小数部分,而是执行 math.floor() 操作,如果要截取小数部分,可以使用 math.trunc() 函数
可以这么说,如果除法的结果都是正数,那么效果是一样的,如果是负数,那么效果就是天差地别了
>>> import math >>> math.trunc(-5 / 2) -2 >>> math.trunc(-5 / 3) -3
5. 异常
-
Python 3.X 添加了
as
关键词来强化异常捕获的可读性Py2.X 中捕获异常一般如下
except Exception, e
Py3.X 中可以如下使用 as
except Exception as e
Py3.X 中还可以这样捕获多个异常
except (Exception1, Exception2) as e
可读性是否大大增强了,以前老是猜 e 到底是啥意思
Python 2.6 已经支持 as 关键字了
-
Py3.X 中只有继承自 BaseException 及其子类的对象才可以被抛出
Py2.x 时代,所有类型的对象都是可以被直接抛出的
-
Py2.x 时代,raise 语句使用逗号将抛出对象类型和参数分开
Py3.x 取消了这种奇葩的写法,直接调用构造函数抛出对象即可
-
Py2.x 时代,异常在代码中除了表示程序错误,还经常做一些普通控制结构应该做的事情
Py3.x 中则只有在错误发生的情况才能去用异常捕获语句来处理
6. xrange
Python 3.X 中废弃了 xrange,起而代之的是重新实现了 range() 完成同样的功能
可以这么理解, Py3.X 中更重视生成器模式,也就是所谓的惰性求值
Py2.X
Python 2 中 xrange() 创建迭代对象的用法是非常流行的,比如: for 循环或者是列表/集合/字典推导式
这个表现十分像生成器(比如 "惰性求值"),但是这个 xrange-iterable 是无穷的,意味着你可以无限遍历
由于它的惰性求值,如果只是需要其中少数几个元素,xrange() 函数 比 range() 更快 (如 for 循环 )
尽管如此,对比迭代一次,不建议重复迭代多次,因为生成器每次都从头开始
Py3.X
Python 3 中已经废弃了 xrange() 函数,起而代之的使用重新实现了 range() 函数
Python 3 中的 range() 函数也会惰性求值了,就像 Py2.X 中的那样
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
7. 八进制字面量表示
-
Py3.X 中 八进制数必须写成
0o777
,原来的形式0777
不能用了0 表示这是数值, o (小写) 其实是八进制 oct 的首字母,这其实是统一格式的要求
python 2.x
>>> 0o1000 512 >>> 01000 512
python 3.x
>>> 01000 File "<stdin>", line 1 01000 ^ SyntaxError: invalid token >>> 0o1000 512
-
Py3.X 中二进制必须写成
0b111
,原来的b111
还能用,但不推荐了0 表示这是数值, b (小写) 其实是二进制 binary 的首字母
-
Py3.X 新增了一个 bin() 函数用于将一个整数转换成二进制字串
上面说到的三点,其实 Python 2.6 就已经支持了
8. 不等运算符
Python 3.x 去掉了 <>
这种不等于号的写法,只保留了 !=
这种写法
其实,Python 2.x 中不等于有两种写法 !=
和 <>
9. 去掉了 repr 表达式 ``
Python 2.x 中反引号 (``) 相当于 repr() 函数的作用
Python 3.x 中去掉了反引号 (``) 这种写法,只允许使用 repr 函数
说不上好不好,但减少了运算符的数量倒是真的,不知道有多少人只记得 str(), 而不识 repr(),更不用说反引号了
10. 多个模块被改名 ( 根据 PEP8 )
根据 PEP8 PY3.X 对 2.X 中的多个模块进行了重新整理
-
改名
旧的名字 新的名字 _winreg winreg ConfigParser configparser copy_reg copyreg Queue queue SocketServer socketserver repr reprlib -
合并
-
StringIO 模块现在被合并到新的 io 模块内
>>> import io >>> so = io.StringIO() >>>
Python 2.6 已经支援新的 io 模块,所以只能算是移除了 StringIO 模块
-
new, md5, gopherlib等模块被删除
所有和 hash 相关的方法都已经移到 hashlib 了
>> import hashlib >>> hashlib.new <function __hash_new at 0x10dcd5ea0> >>> hashlib.md5() <md5 HASH object @ 0x10dfc7a30>
Python 2.6 已经支援 hashlib 模块,所以只能算是移除这些模块了
-
httplib, BaseHTTPServer, CGIHTTPServer, SimpleHTTPServer, Cookie, cookielib 被合并到 http 包内
这个还真是合并了,因为 2.X 系列根本没有 http 包
-
取消了 exec 语句,只剩下 exec() 函数
其实 Python 2.6 已经支持 exec() 函数
-
11. 数据类型
-
Py3.X 去除了 long 类型,现在只有一种整型 ( int ),它的行为就像 2.X 版本的 long
前面我们介绍过, long 其实是 long int ,也就是说 long 类型可以囊括 int 类型
所以我们还可以这么理解,Py3.X 去除了 int 类型,然后把 long 重命名为 int
-
新增了 bytes 类型,对应于 2.X 版本的 八位串
下面的代码定义了一个简单的 bytes 字面量
>>> >>> b = b'Hello' >>> b b'Hello' >>> type(b) <class 'bytes'>
也就是我们在一个字符串前加上 b 就定义了一个 bytes 类型字面量
str 对象和 bytes 对象可以使用 .encode() ( str -> bytes ) or .decode() ( bytes -> str ) 方法相互转化
>>> b = b'Hello' >>> b b'Hello' >>> type(b) <class 'bytes'> >>> s = b.decode() >>> s 'Hello' >>> type(s) <class 'str'> >>> b1 = s.encode() >>> b1 b'Hello' >>> type(b1) <class 'bytes'> >>>
-
字典 ( dict ) 的
.keys()
、.items()
和.values()
方法返回迭代器而之前的
iterkeys()
等函数都被废弃同时去掉的还有
dict.has_key()
,用 in 替代它吧