python 2.7.x 和 3.x 版本区别
来源:互联网 发布:速达软件问题 编辑:程序博客网 时间:2024/06/05 07:21
http://nbviewer.ipython.org/github/rasbt/python_reference/blob/master/tutorials/key_differences_between_python_2_and_3.ipynb
Key differences between Python 2.7.x and Python 3.x
Many beginning Python users are wondering with which version of Python they should start. My answer to this question is usually something along the lines "just go with the version your favorite tutorial was written in, and check out the differences later on."
But what if you are starting a new project and have the choice to pick? I would say there is currently no "right" or "wrong" as long as both Python 2.7.x and Python 3.x support the libraries that you are planning to use. However, it is worthwhile to have a look at the major differences between those two most popular versions of Python to avoid common pitfalls when writing the code for either one of them, or if you are planning to port your project.
Sections
Using the
__future__
moduleThe print function
Integer division
Unicode
xrange
Raising exceptions
Handling exceptions
The next() function and .next() method
For-loop variables and the global namespace leak
Comparing unorderable types
Parsing user inputs via input()
Returning iterable objects instead of lists
More articles about Python 2 and Python 3
The __future__
module
Python 3.x introduced some Python 2-incompatible keywords and features that can be imported via the in-built __future__
module in Python 2. It is recommended to use__future__
imports it if you are planning Python 3.x support for your code. For example, if we want Python 3.x's integer division behavior in Python 2, we can import it via
from __future__ import division
More features that can be imported from the __future__
module are listed in the table below:
from platform import python_version
The print function
[back to the section-overview]
Very trivial, and the change in the print-syntax is probably the most widely known change, but still it is worth mentioning: Python 2's print statement has been replaced by the print()
function, meaning that we have to wrap the object that we want to print in parantheses.
Python 2 doesn't have a problem with additional parantheses, but in contrast, Python 3 would raise a SyntaxError
if we called the print function the Python 2-way without the parentheses.
Python 2
print 'Python', python_version()print 'Hello, World!'print('Hello, World!')print "text", ; print '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')
print 'Hello, World!'
Note:
Printing "Hello, World" above via Python 2 looked quite "normal". However, if we have multiple objects inside the parantheses, we will create a tuple, since print
is a "statement" in Python 2, not a function call.
print 'Python', python_version()print('a', 'b')print 'a', 'b'
Integer division
[back to the section-overview]
This change is particularly dangerous if you are porting code, or if you are executing Python 3 code in Python 2, since the change in integer-division behavior can often go unnoticed (it doesn't raise a SyntaxError
).
So, I still tend to use a float(3)/2
or 3/2.0
instead of a 3/2
in my Python 3 scripts to save the Python 2 guys some trouble (and vice versa, I recommend afrom __future__ import division
in your Python 2 scripts).
Python 2
print 'Python', python_version()print '3 / 2 =', 3 / 2print '3 // 2 =', 3 // 2print '3 / 2.0 =', 3 / 2.0print '3 // 2.0 =', 3 // 2.0
Python 3
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)
Unicode
[back to the section-overview]
Python 2 has ASCII str()
types, separate unicode()
, but no byte
type.
Now, in Python 3, we finally have Unicode (utf-8) str
ings, and 2 byte classes: byte
and bytearray
s.
Python 2
print 'Python', python_version()
print type(unicode('this is like a python3 str type'))
print type(b'byte type does not exist')
print 'they are really' + b' the same'
print type(bytearray(b'bytearray oddly does exist though'))
Python 3
print('Python', python_version())print('strings are now utf-8 \u03BCnico\u0394é!')
print('Python', python_version(), end="")print(' has', type(b' bytes for storing data'))
print('and Python', python_version(), end="")print(' also has', type(bytearray(b'bytearrays')))
'note that we cannot add a string' + b'bytes for data'
xrange
[back to the section-overview]
The usage of xrange()
is very popular in Python 2.x for creating an iterable object, e.g., in a for-loop or list/set-dictionary-comprehension.
The behavior was quite similar to a generator (i.e., "lazy evaluation"), but here the xrange-iterable is not exhaustible - meaning, you could iterate over it infinitely.
Thanks to its "lazy-evaluation", the advantage of the regular range()
is that xrange()
is generally faster if you have to iterate over it only once (e.g., in a for-loop). However, in contrast to 1-time iterations, it is not recommended if you repeat the iteration multiple times, since the generation happens every time from scratch!
In Python 3, the range()
was implemented like the xrange()
function so that a dedicated xrange()
function does not exist anymore (xrange()
raises a NameError
in Python 3).
import timeitn = 10000def 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 3
print('Python', python_version())print('\ntiming range()')%timeit test_range(n)
print(xrange(10))
The __contains__
method for range
objects in Python 3
Another thing worth mentioning is that range
got a "new" __contains__
method in Python 3.x (thanks to Yuchen Ying, who pointed this out). The __contains__
method can speedup "look-ups" in Python 3.x range
significantly for integer and Boolean types.
x = 10000000
def val_in_range(x, val): return val in range(x)
def val_in_xrange(x, val): return val in xrange(x)
print('Python', python_version())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)
Based on the timeit
results above, you see that the execution for the "look up" was about 60,000 faster when it was of an integer type rather than a float. However, since Python 2.x's range
or xrange
doesn't have a __contains__
method, the "look-up speed" wouldn't be that much different for integers or floats:
print 'Python', python_version()assert(val_in_xrange(x, x/2.0) == True)assert(val_in_xrange(x, x/2) == True)assert(val_in_range(x, x/2) == True)assert(val_in_range(x, x//2) == True)%timeit val_in_xrange(x, x/2.0)%timeit val_in_xrange(x, x/2)%timeit val_in_range(x, x/2.0)%timeit val_in_range(x, x/2)
Below the "proofs" that the __contain__
method wasn't added to Python 2.x yet:
print('Python', python_version())range.__contains__
print 'Python', python_version()range.__contains__
print 'Python', python_version()xrange.__contains__
Note about the speed differences in Python 2 and 3
Some people pointed out the speed difference between Python 3's range()
and Python2's xrange()
. Since they are implemented the same way one would expect the same speed. However the difference here just comes from the fact that Python 3 generally tends to run slower than Python 2.
def test_while(): i = 0 while i < 20000: i += 1 return
print('Python', python_version())%timeit test_while()
print 'Python', python_version()%timeit test_while()
Raising exceptions
[back to the section-overview]
Where Python 2 accepts both notations, the 'old' and the 'new' syntax, Python 3 chokes (and raises a SyntaxError
in turn) if we don't enclose the exception argument in parentheses:
Python 2
print 'Python', python_version()
raise IOError, "file error"
raise IOError("file error")
Python 3
print('Python', python_version())
raise IOError, "file error"
The proper way to raise an exception in Python 3:
print('Python', python_version())raise IOError("file error")
Handling exceptions
[back to the section-overview]
Also the handling of exceptions has slightly changed in Python 3. In Python 3 we have to use the "as
" keyword now
Python 2
print 'Python', python_version()try: let_us_cause_a_NameErrorexcept NameError, err: print err, '--> our error message'
Python 3
print('Python', python_version())try: let_us_cause_a_NameErrorexcept NameError as err: print(err, '--> our error message')
The next() function and .next() method
[back to the section-overview]
Since next()
(.next()
) is such a commonly used function (method), this is another syntax change (or rather change in implementation) that is worth mentioning: where you can use both the function and method syntax in Python 2.7.5, the next()
function is all that remains in Python 3 (calling the .next()
method raises anAttributeError
).
Python 2
print 'Python', python_version()my_generator = (letter for letter in 'abcdefg')next(my_generator)my_generator.next()
Python 3
print('Python', python_version())my_generator = (letter for letter in 'abcdefg')next(my_generator)
my_generator.next()
For-loop variables and the global namespace leak
[back to the section-overview]
Good news is: In Python 3.x for-loop variables don't leak into the global namespace anymore!
This goes back to a change that was made in Python 3.x and is described in What’s New In Python 3.0 as follows:
"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."
Python 2
print 'Python', python_version()i = 1print 'before: i =', iprint 'comprehension: ', [i for i in range(5)]print 'after: i =', i
Python 3
print('Python', python_version())i = 1print('before: i =', i)print('comprehension:', [i for i in range(5)])print('after: i =', i)
Comparing unorderable types
[back to the section-overview]
Another nice change in Python 3 is that a TypeError
is raised as warning if we try to compare unorderable types.
Python 2
print 'Python', python_version()print "[1, 2] > 'foo' = ", [1, 2] > 'foo'print "(1, 2) > 'foo' = ", (1, 2) > 'foo'print "[1, 2] > (1, 2) = ", [1, 2] > (1, 2)
Python 3
print('Python', python_version())print("[1, 2] > 'foo' = ", [1, 2] > 'foo')print("(1, 2) > 'foo' = ", (1, 2) > 'foo')print("[1, 2] > (1, 2) = ", [1, 2] > (1, 2))
Parsing user inputs via input()
[back to the section-overview]
Fortunately, the input()
function was fixed in Python 3 so that it always stores the user inputs as str
objects. In order to avoid the dangerous behavior in Python 2 to read in other types than strings
, we have to use raw_input()
instead.
Python 2
Python 2.7.6 [GCC 4.0.1 (Apple Inc. build 5493)] on darwinType "help", "copyright", "credits" or "license" for more information.>>> 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
Python 3.4.1 [GCC 4.2.1 (Apple Inc. build 5577)] on darwinType "help", "copyright", "credits" or "license" for more information.>>> my_input = input('enter a number: ')
enter a number: 123
>>> type(my_input)<class 'str'>
Returning iterable objects instead of lists
[back to the section-overview]
As we have already seen in the xrange
section, some functions and methods return iterable objects in Python 3 now - instead of lists in Python 2.
Since we usually iterate over those only once anyway, I think this change makes a lot of sense to save memory. However, it is also possible - in contrast to generators - to iterate over those multiple times if needed, it is aonly not so efficient.
And for those cases where we really need the list
-objects, we can simply convert the iterable object into a list
via the list()
function.
Python 2
print 'Python', python_version() print range(3) print type(range(3))
Python 3
print('Python', python_version())print(range(3))print(type(range(3)))print(list(range(3)))
Some more commonly used functions and methods that don't return lists anymore in Python 3:
zip()
map()
filter()
dictionary's
.keys()
methoddictionary's
.values()
methoddictionary's
.items()
method
Key differences between Python 2.7.x and Python 3.x
Many beginning Python users are wondering with which version of Python they should start. My answer to this question is usually something along the lines "just go with the version your favorite tutorial was written in, and check out the differences later on."
But what if you are starting a new project and have the choice to pick? I would say there is currently no "right" or "wrong" as long as both Python 2.7.x and Python 3.x support the libraries that you are planning to use. However, it is worthwhile to have a look at the major differences between those two most popular versions of Python to avoid common pitfalls when writing the code for either one of them, or if you are planning to port your project.
Sections
Using the
__future__
moduleThe print function
Integer division
Unicode
xrange
Raising exceptions
Handling exceptions
The next() function and .next() method
For-loop variables and the global namespace leak
Comparing unorderable types
Parsing user inputs via input()
Returning iterable objects instead of lists
More articles about Python 2 and Python 3
The __future__
module
Python 3.x introduced some Python 2-incompatible keywords and features that can be imported via the in-built __future__
module in Python 2. It is recommended to use__future__
imports it if you are planning Python 3.x support for your code. For example, if we want Python 3.x's integer division behavior in Python 2, we can import it via
from __future__ import division
More features that can be imported from the __future__
module are listed in the table below:
from platform import python_version
The print function
[back to the section-overview]
Very trivial, and the change in the print-syntax is probably the most widely known change, but still it is worth mentioning: Python 2's print statement has been replaced by the print()
function, meaning that we have to wrap the object that we want to print in parantheses.
Python 2 doesn't have a problem with additional parantheses, but in contrast, Python 3 would raise a SyntaxError
if we called the print function the Python 2-way without the parentheses.
Python 2
print 'Python', python_version()print 'Hello, World!'print('Hello, World!')print "text", ; print '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')
print 'Hello, World!'
Note:
Printing "Hello, World" above via Python 2 looked quite "normal". However, if we have multiple objects inside the parantheses, we will create a tuple, since print
is a "statement" in Python 2, not a function call.
print 'Python', python_version()print('a', 'b')print 'a', 'b'
Integer division
[back to the section-overview]
This change is particularly dangerous if you are porting code, or if you are executing Python 3 code in Python 2, since the change in integer-division behavior can often go unnoticed (it doesn't raise a SyntaxError
).
So, I still tend to use a float(3)/2
or 3/2.0
instead of a 3/2
in my Python 3 scripts to save the Python 2 guys some trouble (and vice versa, I recommend afrom __future__ import division
in your Python 2 scripts).
Python 2
print 'Python', python_version()print '3 / 2 =', 3 / 2print '3 // 2 =', 3 // 2print '3 / 2.0 =', 3 / 2.0print '3 // 2.0 =', 3 // 2.0
Python 3
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)
Unicode
[back to the section-overview]
Python 2 has ASCII str()
types, separate unicode()
, but no byte
type.
Now, in Python 3, we finally have Unicode (utf-8) str
ings, and 2 byte classes: byte
and bytearray
s.
Python 2
print 'Python', python_version()
print type(unicode('this is like a python3 str type'))
print type(b'byte type does not exist')
print 'they are really' + b' the same'
print type(bytearray(b'bytearray oddly does exist though'))
Python 3
print('Python', python_version())print('strings are now utf-8 \u03BCnico\u0394é!')
print('Python', python_version(), end="")print(' has', type(b' bytes for storing data'))
print('and Python', python_version(), end="")print(' also has', type(bytearray(b'bytearrays')))
'note that we cannot add a string' + b'bytes for data'
xrange
[back to the section-overview]
The usage of xrange()
is very popular in Python 2.x for creating an iterable object, e.g., in a for-loop or list/set-dictionary-comprehension.
The behavior was quite similar to a generator (i.e., "lazy evaluation"), but here the xrange-iterable is not exhaustible - meaning, you could iterate over it infinitely.
Thanks to its "lazy-evaluation", the advantage of the regular range()
is that xrange()
is generally faster if you have to iterate over it only once (e.g., in a for-loop). However, in contrast to 1-time iterations, it is not recommended if you repeat the iteration multiple times, since the generation happens every time from scratch!
In Python 3, the range()
was implemented like the xrange()
function so that a dedicated xrange()
function does not exist anymore (xrange()
raises a NameError
in Python 3).
import timeitn = 10000def 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 3
print('Python', python_version())print('\ntiming range()')%timeit test_range(n)
print(xrange(10))
The __contains__
method for range
objects in Python 3
Another thing worth mentioning is that range
got a "new" __contains__
method in Python 3.x (thanks to Yuchen Ying, who pointed this out). The __contains__
method can speedup "look-ups" in Python 3.x range
significantly for integer and Boolean types.
x = 10000000
def val_in_range(x, val): return val in range(x)
def val_in_xrange(x, val): return val in xrange(x)
print('Python', python_version())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)
Based on the timeit
results above, you see that the execution for the "look up" was about 60,000 faster when it was of an integer type rather than a float. However, since Python 2.x's range
or xrange
doesn't have a __contains__
method, the "look-up speed" wouldn't be that much different for integers or floats:
print 'Python', python_version()assert(val_in_xrange(x, x/2.0) == True)assert(val_in_xrange(x, x/2) == True)assert(val_in_range(x, x/2) == True)assert(val_in_range(x, x//2) == True)%timeit val_in_xrange(x, x/2.0)%timeit val_in_xrange(x, x/2)%timeit val_in_range(x, x/2.0)%timeit val_in_range(x, x/2)
Below the "proofs" that the __contain__
method wasn't added to Python 2.x yet:
print('Python', python_version())range.__contains__
print 'Python', python_version()range.__contains__
print 'Python', python_version()xrange.__contains__
Note about the speed differences in Python 2 and 3
Some people pointed out the speed difference between Python 3's range()
and Python2's xrange()
. Since they are implemented the same way one would expect the same speed. However the difference here just comes from the fact that Python 3 generally tends to run slower than Python 2.
def test_while(): i = 0 while i < 20000: i += 1 return
print('Python', python_version())%timeit test_while()
print 'Python', python_version()%timeit test_while()
Raising exceptions
[back to the section-overview]
Where Python 2 accepts both notations, the 'old' and the 'new' syntax, Python 3 chokes (and raises a SyntaxError
in turn) if we don't enclose the exception argument in parentheses:
Python 2
print 'Python', python_version()
raise IOError, "file error"
raise IOError("file error")
Python 3
print('Python', python_version())
raise IOError, "file error"
The proper way to raise an exception in Python 3:
print('Python', python_version())raise IOError("file error")
Handling exceptions
[back to the section-overview]
Also the handling of exceptions has slightly changed in Python 3. In Python 3 we have to use the "as
" keyword now
Python 2
print 'Python', python_version()try: let_us_cause_a_NameErrorexcept NameError, err: print err, '--> our error message'
Python 3
print('Python', python_version())try: let_us_cause_a_NameErrorexcept NameError as err: print(err, '--> our error message')
The next() function and .next() method
[back to the section-overview]
Since next()
(.next()
) is such a commonly used function (method), this is another syntax change (or rather change in implementation) that is worth mentioning: where you can use both the function and method syntax in Python 2.7.5, the next()
function is all that remains in Python 3 (calling the .next()
method raises anAttributeError
).
Python 2
print 'Python', python_version()my_generator = (letter for letter in 'abcdefg')next(my_generator)my_generator.next()
Python 3
print('Python', python_version())my_generator = (letter for letter in 'abcdefg')next(my_generator)
my_generator.next()
For-loop variables and the global namespace leak
[back to the section-overview]
Good news is: In Python 3.x for-loop variables don't leak into the global namespace anymore!
This goes back to a change that was made in Python 3.x and is described in What’s New In Python 3.0 as follows:
"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."
Python 2
print 'Python', python_version()i = 1print 'before: i =', iprint 'comprehension: ', [i for i in range(5)]print 'after: i =', i
Python 3
print('Python', python_version())i = 1print('before: i =', i)print('comprehension:', [i for i in range(5)])print('after: i =', i)
Comparing unorderable types
[back to the section-overview]
Another nice change in Python 3 is that a TypeError
is raised as warning if we try to compare unorderable types.
Python 2
print 'Python', python_version()print "[1, 2] > 'foo' = ", [1, 2] > 'foo'print "(1, 2) > 'foo' = ", (1, 2) > 'foo'print "[1, 2] > (1, 2) = ", [1, 2] > (1, 2)
Python 3
print('Python', python_version())print("[1, 2] > 'foo' = ", [1, 2] > 'foo')print("(1, 2) > 'foo' = ", (1, 2) > 'foo')print("[1, 2] > (1, 2) = ", [1, 2] > (1, 2))
Parsing user inputs via input()
[back to the section-overview]
Fortunately, the input()
function was fixed in Python 3 so that it always stores the user inputs as str
objects. In order to avoid the dangerous behavior in Python 2 to read in other types than strings
, we have to use raw_input()
instead.
Python 2
Python 2.7.6 [GCC 4.0.1 (Apple Inc. build 5493)] on darwinType "help", "copyright", "credits" or "license" for more information.>>> 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
Python 3.4.1 [GCC 4.2.1 (Apple Inc. build 5577)] on darwinType "help", "copyright", "credits" or "license" for more information.>>> my_input = input('enter a number: ')
enter a number: 123
>>> type(my_input)<class 'str'>
Returning iterable objects instead of lists
[back to the section-overview]
As we have already seen in the xrange
section, some functions and methods return iterable objects in Python 3 now - instead of lists in Python 2.
Since we usually iterate over those only once anyway, I think this change makes a lot of sense to save memory. However, it is also possible - in contrast to generators - to iterate over those multiple times if needed, it is aonly not so efficient.
And for those cases where we really need the list
-objects, we can simply convert the iterable object into a list
via the list()
function.
Python 2
print 'Python', python_version() print range(3) print type(range(3))
Python 3
print('Python', python_version())print(range(3))print(type(range(3)))print(list(range(3)))
Some more commonly used functions and methods that don't return lists anymore in Python 3:
zip()
map()
filter()
dictionary's
.keys()
methoddictionary's
.values()
methoddictionary's
.items()
method
- python 2.7.x 和 3.x 版本区别
- Python 2.7.x 和 3.x 版本的重要区别
- Python 2.7.x 和 3.x 版本的重要区别
- Python 2.7.x 和 3.x 版本的重要区别
- Python 2.7.x 和 3.x 版本的重要区别
- Python 2.7.x 和 3.x 版本的区别
- Python 2.7.x 和 3.x 版本的重要区别
- Python 2.7.x 和 3.x 版本的重要区别
- Python 2.7.x 和 3.x 版本的重要区别
- Python 2.7.x 和 3.x 版本的重要区别
- Python 2.7.x 和 3.x 版本的重要区别
- Python-3.X和2.X版本的区别
- Python 2.7.x 和 3.x 版本的重要区别小结
- Python 2.7.x 和 3.x 版本的重要区别小结
- [转] Python 2.7.x 和 3.x 版本的重要区别小结
- Python 2.7.x 和 3.x 版本的重要区别小结
- Python 2.7.x 和 3.x 版本的重要区别小结
- Python 2.7.x 和 3.x 版本的重要区别小结
- 四十二 毕设(中) 我在软件园的那些日子里
- 更改WebStrom主题字体
- Dirichlet Process and Hierarchical Dirichlet Process
- innerHTML和html联系和区别
- ZIP压缩算法详细分析及解压实例解释
- python 2.7.x 和 3.x 版本区别
- vijos1070_关于次小生成树的求法
- CSS:class选择器的使用
- Redis事务
- 使用charles proxy for Mac来抓取手机App的网络包
- 编译bluez-5.25 遇到的错误及解决方法
- asp.net中Session小例子
- AndroidManifest.xml中的<uses-feature/>以及和<uses-permission/>之间的联系
- HDOJ 5128 The E-pang Palace 暴力枚举+计算几何