您的位置:首页 > 编程语言 > Python开发

python2.7和 python3.4的却别

2016-05-18 15:37 686 查看
许多 Python 初学者想知道他们应该从 Python 的哪个版本开始学习。对于这个问题我的答案是 “你学习你喜欢的教程的版本,然后检查他们之间的不同。"

但是如果你开始一个新项目,并且有选择权?我想说的是目前没有对错,只要你计划使用的库 Python 2.7.x 和 Python 3.x 双方都支持的话。尽管如此,当在编写它们中的任何一个的代码,或者是你计划移植你的项目的时候,是非常值得看看这两个主要流行的 Python 版本之间的差别的,以便避免常见的陷阱,


章节

使用
__future__
模块

print
函数

Integer
division
Unicode
xrange
Raising
exceptions
Handling
exceptions
next()
函数
.next()
方法
For
循环变量和全局命名空间泄漏
比较不可排序类型
通过
input()
解析用户的输入

返回可迭代对象,而不是列表
更多的关于
Python 2 和 Python 3 的文章


future 模块

Python 3.x 介绍的 一些Python 2 不兼容的关键字和特性可以通过在 Python 2 的内置
__future__
模块导入。如果你计划让你的代码支持 Python 3.x,建议你使用
__future__
模块导入。例如,如果我想要
在Python 2 中表现 Python 3.x 中的整除,我们可以通过如下导入
from __future__ import division


更多的
__future__
模块可被导入的特性被列在下表中:
featureoptional inmandatory ineffect
nested_scopes2.1.0b12.2PEP
255 : Simple Generators
division2.2.0a23.0PEP
328 : Imports: Multi-Line and Absolute/Relative
with_statement2.5.0a12.6PEP
3105 : Make print a function
unicode_literals2.6.0a23.0<a rel="nofollow" href="http://legacy.python.org/dev/peps/pep-3112/" """="" target="_blank" style="color: rgb(128, 0, 128); text-decoration: none; outline-style: none;">PEP 3112: Bytes literals in Python 3000
(Source: https://docs.python.org/2/library/future.html )
from platform import python_version


print函数

[跳转到章节预览]

很琐碎,而
print
语法的变化可能是最广为人知的了,但是仍值得一提的是: Python 2 的
print
声明已经被
print()
函数取代了,这意味着我们必须包装我们想打印在小括号中的对象。

Python 2 不具有额外的小括号问题。但对比一下,如果我们按照 Python 2 的方式不使用小括号调用
print
函数,Python 3 将抛出一个语法异常(
SyntaxError
)。


Python 2

print 'Python', python_version()
print 'Hello, World!'
print('Hello, World!') print "text", ; print 'print more text on the same line'

Python 2.7.6
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 2 使用
Printing "Hello, World"
是非常正常的,尽管如此,如果你有多个对象在小括号中,我们将创建一个元组,因为
print

Python 2 中是一个声明,而不是一个函数调用。
print 'Python', python_version()
print('a', 'b') print 'a', 'b'

Python 2.7.7
('a', 'b')
a b


整除

[跳转到章节预览]

如果你正在移植代码,这个变化是特别危险的。或者你在 Python 2 上执行 Python 3 的代码。因为这个整除的变化表现在它会被忽视(即它不会抛出语法异常)。

因此,我还是倾向于使用一个
float(3)/2
3/2.0
代替在我的
Python 3 脚本保存在 Python 2 中的
3/2
的一些麻烦(并且反而过来也一样,我建议在你的 Python 2 脚本中使用
from
__future__ import division


Python 2

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

Python 2.7.6
3 / 2 = 1
3 // 2 = 1
3 / 2.0 = 1.5
3 // 2.0 = 1.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)

Python 3.4.1
3 / 2 = 1.5
3 // 2 = 1
3 / 2.0 = 1.5
3 // 2.0 = 1.0


Unicode

[跳转到章节预览]

Python 2 有
ASCII str()
类型,
unicode()
是单独的,不是
byte 类型。

现在, 在 Python 3,我们最终有了
Unicode (utf-8)
字符串,以及一个字节类:
byte
bytearrays


Python 2

print 'Python', python_version()

Python 2.7.6

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

print('Python', python_version()) print('strings are now utf-8 u03BCnicou0394é!')  Python 3.4.1 strings are now utf-8 μnicoΔé!

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


xrange

[跳转到章节预览]

在 Python 2 中
xrange()
创建迭代对象的用法是非常流行的。比如: for 循环或者是列表/集合/字典推导式。

这个表现十分像生成器(比如。“惰性求值”)。但是这个
xrange-iterable
是无穷的,意味着你可以无限遍历。

由于它的惰性求值,如果你不得仅仅不遍历它一次,
xrange()
函数 比
range()
更快(比如
for 循环)。尽管如此,对比迭代一次,不建议你重复迭代多次,因为生成器每次都从头开始。

在 Python 3 中,
range()
是像
xrange()
那样实现以至于一个专门的
xrange()
函数都不再存在(在
Python 3 中
xrange()
会抛出命名异常)。
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 'nntiming 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


Python 3 中的
range
对象的
__contains__
方法

另外一件值得一提的事情就是在 Python 3 中
range
有一个新的
__contains__
方法(感谢 Yuchen
Ying 指出了这个),
__contains__
方法可以加速
"查找"

Python 3.x 中显著的整数和布尔类型。
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)
Python 3.4.1
1 loops, best of 3: 742 ms per loop
1000000 loops, best of 3: 1.19 µs per loop


基于以上的
timeit
的结果,当它使一个整数类型,而不是浮点类型的时候,你可以看到执行查找的速度是 60000 倍快。尽管如此,因为 Python 2.x 的
range
或者是
xrange
没有一个
__contains__
方法,这个整数类型或者是浮点类型的查询速度不会相差太大。
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)

Python 2.7.7
1 loops, best of 3: 285 ms per loop
1 loops, best of 3: 179 ms per loop
1 loops, best of 3: 658 ms per loop
1 loops, best of 3: 556 ms per loop


下面说下
__contain__
方法并没有加入到 Python 2.x 中的证据:
print('Python', python_version()) range.__contains__  Python 3.4.1  <slot wrapper '__contains__' of 'range' objects>

print 'Python', python_version()
range.__contains__

Python 2.7.7
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-7-05327350dafb> in <module>()       1 print 'Python', python_version() ----> 2 range.__contains__  AttributeError: 'builtin_function_or_method' object has no attribute '__contains__'

print 'Python', python_version()
xrange.__contains__

Python 2.7.7
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-8-7d1a71bfee8e> in <module>()       1 print 'Python', python_version() ----> 2 xrange.__contains__  AttributeError: type object 'xrange' has no attribute '__contains__'


**注意在 Python 2 和 Python 3 中速度的不同***

有些猿类指出了 Python 3 的
range()
和 Python 2 的
xrange()
之间的速度不同。因为他们是用相同的方法实现的,因此期望相同的速度。尽管如此,这事实在于
Python 3 倾向于比 Python 2 运行的慢一点。
def test_while():
i = 0
while i < 20000:
i += 1
return

print('Python', python_version())
%timeit test_while()

Python 3.4.1
100 loops, best of 3: 2.68 ms per loop

print 'Python', python_version()
%timeit test_while()

Python 2.7.6
1000 loops, best of 3: 1.72 ms per loop


Raising exceptions

[跳转到章节预览]

Python 2 接受新旧两种语法标记,在 Python 3 中如果我不用小括号把异常参数括起来就会阻塞(并且反过来引发一个语法异常)。


Python 2

print 'Python', python_version()

Python 2.7.6

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

print('Python', python_version())  Python 3.4.1

raise IOError, "file error"

File "<ipython-input-10-25f049caebb0>", line 1
raise IOError, "file error"
^
SyntaxError: invalid syntax
The proper way to raise an exception in Python 3:

print('Python', python_version()) raise IOError("file error")   Python 3.4.1 --------------------------------------------------------------------------- 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


Handling exceptions

在 Python 3 中处理异常也轻微的改变了,在 Python 3 中我们现在使用
as
作为关键词。


python 2

print 'Python', python_version()
try:
let_us_cause_a_NameError
except NameError, err:
print err, '--> our error message'
Python 2.7.6
name 'let_us_cause_a_NameError' is not defined --> our error message


Python 3

print('Python', python_version())
try:
let_us_cause_a_NameError
except NameError as err:
print(err, '--> our error message')
Python 3.4.1
name 'let_us_cause_a_NameError' is not defined --> our error message


next() 函数 and .next() 方法

因为
next() (.next())
是一个如此普通的使用函数(方法),这里有另外一个语法改变(或者是实现上改变了),值得一提的是:在 Python 2.7.5 中函数和方法你都可以使用,
next()
函数在
Python 3 中一直保留着(调用
.next()
抛出属性异常)。


Python 2

print 'Python', python_version()

my_generator = (letter for letter in 'abcdefg')

next(my_generator) my_generator.next()

Python 2.7.6

'b'


Python 3

print('Python', python_version())  my_generator = (letter for letter in 'abcdefg')  next(my_generator)

Python 3.4.1

'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 循环变量不会再导致命名空间泄漏。

在 Python 3.x 中做了一个改变,在 What’s
New In Python 3.0 中有如下描述:
"列表推导不再支持 [... for var in item1, item2, ...] 这样的语法。使用 [... for var in (item1, item2, ...)] 代替。也需要提醒的是列表推导有不同的语义:  他们关闭了在 `list()` 构造器中的生成器表达式的语法糖, 并且特别是循环控制变量不再泄漏进周围的作用范围域."


Python 2

print 'Python', python_version()

i = 1
print 'before: i =', i

print 'comprehension: ', [i for i in range(5)]

print 'after: i =', i

Python 2.7.6
before: i = 1
comprehension:  [0, 1, 2, 3, 4]
after: i = 4


Python 3

print('Python', python_version())

i = 1
print('before: i =', i)

print('comprehension:', [i for i in range(5)])

print('after: i =', i)

Python 3.4.1
before: i = 1
comprehension: [0, 1, 2, 3, 4]
after: i = 1


比较不可排序类型

在 Python 3 中的另外一个变化就是当对不可排序类型做比较的时候,会抛出一个类型错误。


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 2.7.6
[1, 2] > 'foo' =  False
(1, 2) > 'foo' =  True
[1, 2] > (1, 2) =  False


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))   Python 3.4.1 --------------------------------------------------------------------------- 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 中已经解决了把用户的输入存储为一个
str
对象的问题。为了避免在 Python 2 中的读取非字符串类型的危险行为,我们不得不使用
raw_input()
代替。


Python 2

Python 2.7.6
[GCC 4.0.1 (Apple Inc. build 5493)] on darwin
Type "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 darwin
Type "help", "copyright", "credits" or "license" for more information.

>>> my_input = input('enter a number: ')

enter a number: 123

>>> type(my_input)
<class 'str'>


返回可迭代对象,而不是列表

如果在 xrange 章节看到的,现在在 Python 3 中一些方法和函数返回迭代对象 -- 代替 Python 2 中的列表

因为我们通常那些遍历只有一次,我认为这个改变对节约内存很有意义。尽管如此,它也是可能的,相对于生成器 --- 如需要遍历多次。它是不那么高效的。

而对于那些情况下,我们真正需要的是列表对象,我们可以通过
list()
函数简单的把迭代对象转换成一个列表。


Python 2

print 'Python', python_version()

print range(3)
print type(range(3))

Python 2.7.6
[0, 1, 2]
<type 'list'>


Python 3

print('Python', python_version())  print(range(3)) print(type(range(3))) print(list(range(3)))   Python 3.4.1 range(0, 3) <class 'range'> [0, 1, 2]


在 Python 3 中一些经常使用到的不再返回列表的函数和方法:

zip()

map()

filter()

dictionary's .keys() method

dictionary's .values() method

dictionary's .items() method


更多的关于 Python 2 和 Python 3 的文章

下面是我建议后续的关于 Python 2 和 Python 3 的一些好文章。


移植到 Python 3

Should
I use Python 2 or Python 3 for my development activity?

What’s
New In Python 3.0

Porting
to Python 3

Porting
Python 2 Code to Python 3

How
keep Python 3 moving forward


Python 3 的拥护者和反对者


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: