Python2 和 Python3 最近在面试, 遇到了几个同样的问题, 就是 “python2 和 python3 具体有哪些区别”? 遇到这个问题的时候, 我每次都懵逼, 因为确实除了语法糖以外的区别, 我一个都说不出来. 所以回来之后查了一下资料, 总结出几个主要的区别, 记录下来.
“future” 模块 python3 引入了一些python2 没有的关键字和功能, 如果需要在python2中使用这些功能, 就需要导入__future__模块. 举个例子, 在python3中/是返回一个浮点数, 但是在python2中, 除法操作返回的是一个整数. 如果要在python2中使用python3的除法功能, 就需要引入 __future__模块来支持.
1 2 3 4 5 6 7 8 9 10 11 python 2.7 >>> 1 / 2 0 >>> 1.0 / 2.0 0.5 >>> from __future__ import division>>> 1 / 2 0.5 >>> 1.0 / 2.0 0.5
“print” 语法糖 在python2的语法当中, 如果需要在屏幕上打印的时候, 仅仅需要pring "something". 但是来到python3, 这个函数被print()替代了.
python2 1 2 3 4 print 'Python' , python_version()print 'Hello, World!' print ("Hello, World!" )print "text" , ; print 'print more text on the same line!'
输出
1 2 3 4 Python 2 .7 .6 Hello , World!Hello , World!text print more text on the same line
python3 1 2 3 4 print ('Python' , python_version())print ('Hello, World!' )print ('Some text,' , end="" )print (' print more text on the same line' )
输出
1 2 3 Python 3.4 .1 Hello, World! some text , print more text on the same line
整数除法 整数除法对于python2到python3转换是一个大坑
python2 1 2 3 4 5 print 'Python' , python_version()print '3/2 = ' , 3 /2 print '3//2 = ' , 3 //2 print '3/2.0 = ' , 3 /2.0 print '3//2.0 = ' , 3 //2.0
输出
1 2 3 4 5 Python 2 .7 .6 3 / 2 = 1 3 // 2 = 1 3 / 2 .0 = 1 .5 3 // 2 .0 = 1 .0
python3 1 2 3 4 5 print ('Python' , python_version())print ('3/2 = ' , 3 /2 )print ('3//2 = ' , 3 //2 )print ('3/2.0 = ' , 3 /2.0 )print ('3//2.0 = ' , 3 //2.0 )
输出
1 2 3 4 5 Python 3 .4 .1 3 / 2 = 1 .5 3 // 2 = 1 3 / 2 .0 = 1 .5 3 // 2 .0 = 1 .0
Unicode python2 有ASCII str()类型, 跟unicode()类型并不一样, 而且在python2中没有byte类型. python3 有utf-8 的 str()类型. 同时python3也用byte 和 bytearray
Python2 1 2 3 4 5 6 7 8 >>>print 'Python' , python_version() Python 2.7 .6 >>>type (unicode('this is like py3 str type' )) <type 'unicode' > >>>type (b'byte type does not exist' ) <type 'str' > >>>type (bytearray (b'bytearray oddly exist' )) <type 'bytearray' >
Python3 1 2 3 4 5 6 >>>print ('Python' , python_version()) Python 3.4 .1 >>>print ('strings are utf-8 \u03BCnico\u0394é!' ) strings are now utf-8 μnicoΔé! >>>print ('Python has' , type (b' bytes for storing data' )) Python has <class 'bytes '>
xrange 在python2, xrange()主要被用来构建一个可迭代对象, 实现起来跟generator非常像. 但是xrange并不是有限的, 开发者可以无限地迭代下去. 而在python3, xrange()不复存在了, 取而代之的是 range()这个函数. 如果在python3中调用xrange(), 会被抛一个NameError的异常.
1 2 3 4 5 6 7 8 n = 10000 def range_test (n ): return for i in range (n): pass def xrange_test (n ): for i in xrange(n): pass
对于上面的这个简单的程序, py2和py3各自有着不同的表现.
Python2 1 2 3 4 5 6 7 8 9 10 11 print '\ntiming range()' %timeit range_test(n) print '\ntiming xrange()' %timeit xrange_test(n) >>> timing range ()1000 loops, best of 3 : 433 μs per loop>>> timing xrange()1000 loops, best of 3 : 350 μs per loop
Python3 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 print ("\ntiming range()" )%timeit range_test(n) >>> 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
再有就是, 在python3中, range对象有一个新的字段, 叫__contains__, 对于判断一个元素是否存在于range能加速(前提是int或者boolean).
1 2 3 4 5 6 7 8 9 10 11 12 13 x = 10000000 def val_in_range (x, val ): return val in range (x) assert (val_in_range(x, x/2 ) == True )assert (val_in_range(x, x//2 ) == True )%timeit val_in_range(x, x/2 ) %timeit val_in_range(x, x//2 ) >>> 1 loops, best of 3 : 742 ms per loop1000000 loops, best of 3 : 1.19 μs per loop
从上面的结果来看, 如果元素是整数而不是float的话, 速度要快非常非常多.
抛出异常 python2和python3抛出异常的差异, 仅仅存在于语法层面.
python2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 print 'Python, python_version()' raise IOError, "file error" >>> Python 2.7.6 >>> --------------------------------------------------------------------------- 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
python3 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 raise IOError, "file error" >>> File "<ipython-input-10-25f049caebb0>" , line 1 raise IOError, "file error" ^ SyntaxError: invalid syntax 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
异常处理 既然py2和py3在抛出异常上有语法上的差别, 那么处理异常方面也同样会有一点点语法上的区别.
python2 1 2 3 4 5 6 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
python3 1 2 3 4 5 6 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() 在python3当中, .next()方法已经被取消了, 只剩下next()方法可用. python2 两个方法都继续存在. 如果在python3中调用.nxt(), 系统会抛出异常.
for循环变量和全局空间泄露 python3对比python2的一个重大改变要数python3中, for循环的变量并不会被泄露到全局空间里. 官方文档是这么描述的
“List comprehensions no longer support the syntactic form [… for var in item1, item2, …]. Use [… for var in (item1, item2, …)] instead. Also note that list comprehensions have different semantics: they are closer to syntactic sugar for a generator expression inside a list() constructor, and in particular the loop control variables are no longer leaked into the surrounding scope.”
python2 1 2 3 4 5 6 7 8 i = 1 print 'before: i = ' , iprint 'comprehension: ' , [i for i in range (5 )]print 'after: i = ' , i>>> before: i = 1 comprehension: [0 , 1 , 2 , 3 , 4 ] after: i = 4
pythnon3 1 2 3 4 5 6 7 8 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的异常. 那么什么是不可排序变量呢? 举个例子, 当用list和str()比较, 就是一个不可排序类型的比较.
处理用户输入 在python中, 如果要处理用户的输入, 最常使用的方法是input(). 但是很多开发者不知道的是, 在python2当中, input()所返回的类型并不是固定的, 为了避免一些危险的操作出现, 有经验的python2开发会使用raw_input()而不是input(). 但是, 在python3中, input()的返回类型终于被固定了, 在python3的各个版本当中, inpit()返回的是一个str对象.
python2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 my_input = input ('enter number: ' ) >>> enter number: 123 type (my_input)>>> <type 'int' >my_input = raw_input('enter number: ' ) >>> enter number: 123 type (my_input)>>> <type 'str' >
pythnon3 1 2 3 4 5 6 7 my_input = input ('enter number: ' ) >>> enter number: 123 type (my_input)>>> <type 'str' >