python2与python3的区别总结
大部分Python库都同时支持Python 2.7.x和3.x版本的,所以不论选择哪个版本都是可以的。但为了在使用Python时避开某些版本中一些常见的陷阱,或需要移植某个Python项目时,依然有必要了解一下Python两个常见版本之间的主要区别。
主要区别列表:
- 使用__future__模块(__是两下划线)
- print函数
- 整数除法
- Unicode
- xrange
- 触发异常
- 处理异常
- next()函数和.next()方法
- For循环变量与全局命名空间泄漏
- 比较无序类型
- 使用input()解析输入内容
- 返回可迭代对象,而不是列表
__future__模块
Python 3.x引入了一些与Python 2不兼容的关键字和特性,在Python 2中,可以通过内置的__future__模块导入这些新内容。如果你希望在Python 2环境下写的代码也可以在Python 3.x中运行,那么建议使用__future__模块。例如,如果希望在Python 2中拥有Python 3.x的整数除法行为,可以通过下面的语句导入相应的模块。
from __future__ import division
更多的可导入特性可查看:https://docs.python.org/2/library/future.htm
print函数
Python 2中的print语句被Python 3中的print()函数取代,这意味着在Python 3中必须用括号将需要输出的对象括起来。
Python 2:
from platform import python_version
print 'Python', python_version()
print 'Hello, World!'
print('Hello, World!')
print "text", ; print 'print more text on the same line'
结果:
Python 2.7.13
Hello, World!
Hello, World!
text print more text on the same line
Python 3:
①
print('Python', python_version())
print('Hello, World!')
print("some text,", end="") #打印完不加任何字符
print(' print more text on the same line')
结果:
Python 3.4.1
Hello, World!
some text, print more text on the same line
②
print 'Hello, World!'
结果:
File "<ipython-input-3-139a7c5835bd>", line 1
print 'Hello, World!'
^
SyntaxError: invalid syntax
注意:
在Python中,带不带括号输出”Hello World”都很正常。但如果在圆括号中同时输出多个对象时,就会创建一个元组,这是因为在Python 2中,print是一个语句,而不是函数调用。
print 'Python', python_version()
print('a', 'b')
print 'a', 'b'
结果:
Python 2.7.7
('a', 'b')
a b
整数除法
由于人们常常会忽视Python 3在整数除法上的改动(写错了也不会触发Syntax Error),所以在移植代码或在Python 2中执行Python 3的代码时,需要特别注意这个改动。
所以,我还是会在Python 3的脚本中尝试用float(3)/2或 3/2.0代替3/2,以此来避免代码在Python 2环境下可能导致的错误(或与之相反,在Python 2脚本中用from __future__ import division来使用Python 3的除法)。
在Python2中,除法的取值结果取整数
>>>9/2
4
>>> 3/2.0
1.5
>>> 4/2.0
2.0
而在Python3中,除法/的结果包含小数,如果只想取整数需要使用//
>>> 9/2
4.5
>>> 9//2
4
>>> 3 / 2.0
1.5
>>> 3 // 2.0
1.0
如果在python2中需要实现与python3相同功能的除法,需要导入模块
C:\Users\Administrator>python
Python 2.7.13 |Continuum Analytics, Inc.| (default, May 11 2017, 14:07:41) [MSC
v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> 9/2
4
>>> from __future__ import division
>>> 9/2
4.5
Unicode
Python 2有基于ASCII的str()类型,其可通过单独的unicode()函数转成unicode类型,但没有byte类型。
而在Python 3中,终于有了Unicode(utf-8)字符串,以及两个字节类:bytes和bytearray(没有s)。
注意python2.6以后也有bytearray类。
Python 3 源码文件默认使用utf-8编码,这就使得以下代码是合法的:
>>> 中国 = 'china'
>>>print(中国)
china
Python 2:
>>> 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'
>>> print type(unicode('this is like a python3 str type'))
<type 'unicode'>
>>> print type(b'byte type does not exist')
<type 'str'>
>>> print 'they are really' + b' the same'
they are really the same
>>> print type(bytearray(b'bytearray oddly does exist though'))
<type 'bytearray'>
Python 3:
>>> str = "我爱北京天安门"
>>> str
'我爱北京天安门'
>>> print('Python', python_version(), end="")
>>> print(' has', type(b' bytes for storing data'))
Python 3.4.1 has <class 'bytes'>
>>> print('and Python', python_version(), end="")
>>> print(' also has', type(bytearray(b'bytearrays')))
and Python 3.4.1 also has <class 'bytearray'>
>>> 'note that we cannot add a string' + b'bytes for data'
TypeError Traceback (most recent call last)
<ipython-input-13-d3e8942ccf81> in <module>()
----> 1 'note that we cannot add a string' + b'bytes for data'
TypeError: Can't convert 'bytes' object to str implicitly
注意:
在python2.x中,unicode字符串需要在字符串前加u来表示,比如
str=u'汉字'
而在python3.x中,unicode字符串已经是默认格式,因此不再需要加u,如果你加了u,会报语法错误:
str=u'汉字'
SyntaxError: invalid syntax
python2.x里, b前缀没什么具体意义, 只是为了兼容python3.x的这种写法
由于python3默认编码的改动,可以用中文当作变量,也就看到有人写下了如此凶残的代码:
xrange
1.Py2.x
1).range 和xrange都是经常使用的,特别是range()返回一个列表
>>>print range(3)
[0, 1, 2]
2).xrange()一般用来创建迭代对象
>>>print [x for x in xrange(3)]
[0, 1, 2]
>>>print list(xrange(3))
[0, 1, 2]
2.Py3.x
3).里面xrange()不存在了,只有range().而range()相当于py2.x里面的xrange()
>>>print (range(3))
range(0, 3)
想要获取列表,必须要加list
>>>print (list(range(3)))
[0, 1, 2]
感悟:其实主要对内存的节约,py2.x里面比如你range(10000),一下子就生成一个长度为10000的内存空间,而py3的 range(1000)返回的不是列表是一个迭代器,你用的时候一个一个循环取出来,对内存节省很多。
Python 3中的range对象中的contains方法
在Python 3.x中,range有了一个新的contains方法。contains方法可以有效的加快Python 3.x中整数和布尔型的“查找”速度。
python3中查找整数比查找浮点数要快大约6万倍,而python2中几乎无差别。
这里不细说明,知道有这么点改动就好。
其实,Python 3中的range()和Python 2中xrange()执行速度有差异。由于这两者的实现方式相同,因此理论上执行速度应该也是相同的。这里的速度差别仅仅是因为Python 3的总体速度就比Python 2慢。
触发异常
Python 2支持新旧两种异常触发语法,而Python 3只接受带括号的的语法(不然会触发SyntaxError):
Python 2:
①
>>>raise IOError, "file error"
IOError Traceback (most recent call last)
<ipython-input-8-25f049caebb0> in <module>()
----> 1 raise IOError, "file error"
IOError: file error
②
>>>raise IOError("file error")
IOError Traceback (most recent call last)
<ipython-input-9-6f1c43f525b2> in <module>()
----> 1 raise IOError("file error")
IOError: file error
python 3:
>>>raise IOError("file error")
OSError Traceback (most recent call last)
<ipython-input-11-c350544d15da> in <module>()
1 print('Python', python_version())
----> 2 raise IOError("file error")
OSError: file error
异常处理
Python 2:
try:
let_us_cause_a_NameError
except NameError, err:
print err, '--> our error message'
结果:
name 'let_us_cause_a_NameError' is not defined --> our error message
python 3:
try:
let_us_cause_a_NameError
except NameError as err:
print(err, '--> our error message')
结果:
name 'let_us_cause_a_NameError' is not defined --> our error message
next()函数和.next()方法
在Python 2.7.5中,函数形式和方法形式都可以使用。
在Python 3中,只能使用next()函数(试图调用.next()方法会触发AttributeError)。
Python 2:
my_generator = (letter for letter in 'abcdefg')
next(my_generator)
my_generator.next()
结果:
'a'
'b'
python 3:
①
my_generator = (letter for letter in 'abcdefg')
next(my_generator)
结果:
'a'
②
my_generator.next()
结果:
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-14-125f388bb61b> in <module>()
----> 1 my_generator.next()
AttributeError: 'generator' object has no attribute 'next'
For循环变量与全局命名空间泄漏
在Python 3.x中,for循环中的变量不再会泄漏到全局命名空间中了!
(记否:在函数定义中声明的变量,他们与在函数外使用的其他同名变量没有任何关系,即变量名称对函数来说是局部的)
列表推导不再支持[… for var in item1, item2, …]这样的语法,使用[… for var in (item1, item2, …)]代替。还要注意列表推导有不同的语义:现在列表推导更接近list()构造器中的生成器表达式这样的语法糖,特别要注意的是,循环控制变量不会再泄漏到循环周围的空间中了。
Python 2:
i = 1
print 'before: i =', i
print 'comprehension: ', [i for i in range(5)]
print 'after: i =', i
结果:
before: i = 1
comprehension: [0, 1, 2, 3, 4]
after: i = 4
Python 3:
i = 1
print('before: i =', i)
print('comprehension:', [i for i in range(5)])
print('after: i =', i)
结果:
before: i = 1
comprehension: [0, 1, 2, 3, 4]
after: i = 1
比较无序类型
python3中试图比较无序类型,会触发一个TypeError,python2不会。
Python 2:
print "[1, 2] > 'foo' = ", [1, 2] > 'foo'
print "(1, 2) > 'foo' = ", (1, 2) > 'foo'
print "[1, 2] > (1, 2) = ", [1, 2] > (1, 2)
结果:
[1, 2] > 'foo' = False
(1, 2) > 'foo' = True
[1, 2] > (1, 2) = False
Python 3:
print("[1, 2] > 'foo' = ", [1, 2] > 'foo')
print("(1, 2) > 'foo' = ", (1, 2) > 'foo')
print("[1, 2] > (1, 2) = ", [1, 2] > (1, 2))
结果:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-16-a9031729f4a0> in <module>()
1 print('Python', python_version())
----> 2 print("[1, 2] > 'foo' = ", [1, 2] > 'foo')
3 print("(1, 2) > 'foo' = ", (1, 2) > 'foo')
4 print("[1, 2] > (1, 2) = ", [1, 2] > (1, 2))
TypeError: unorderable types: list() > str()
通过input()解析用户的输入
Python 3改进了input()函数,这样该函数就会总是将用户的输入存储为str对象。在Python 2中,为了避免读取非字符串类型会发生的一些危险行为,不得不使用raw_input()代替input()。
python只有input()了。
Python 2:
①
>>> my_input = input('enter a number: ')
enter a number: 123
>>> type(my_input)
<type 'int'>
②
>>> my_input = raw_input('enter a number: ')
enter a number: 123
>>> type(my_input)
<type 'str'>
Python 3:
>>> my_input = input('enter a number: ')
enter a number: 123
>>> type(my_input)
<class 'str'>
返回可迭代对象,而不是列表
python3进行了改进。由于通常对这些对象只遍历一次,所以这种方式会节省很多内存。然而,如果通过生成器来多次迭代这些对象,效率就不高了。此时我们的确需要列表对象,可以通过list()函数简单的将可迭代对象转成列表。
下面列出了Python 3中不再返回列表的常用函数和方法:
- range
- zip()
- map()
- filter()
- 字典的.key()方法
- 字典的.value()方法
- 字典的.item()方法
Python 2:
print range(3)
print type(range(3))
结果:
[0, 1, 2]
<type 'list'>
Python 3:
print(range(3))
print(type(range(3)))
print(list(range(3)))
结果:
range(0, 3)
<class 'range'>
[0, 1, 2]