python x x 3_转:python2.x 和 python3.x的区别

许多 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 的文章

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_scopes

2.1.0b1

2.2

PEP 227: Statically Nested Scopes

generators

2.2.0a1

2.3

PEP 255: Simple Generators

division

2.2.0a2

3.0

PEP 238: Changing the Division Operator

absolute_import

2.5.0a1

3.0

PEP 328: Imports: Multi-Line and Absolute/Relative

with_statement

2.5.0a1

2.6

PEP 343: The “with” Statement

print_function

2.6.0a2

3.0

PEP 3105: Make print a function

unicode_literals

2.6.0a2

3.0

PEP 3112: Bytes literals in Python 3000

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'Python2.7.6Hello, World!

Hello, World!

textprint 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')

Python3.4.1Hello, World!

some text,printmore text on the same lineprint 'Hello, World!'File"", 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'Python2.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.0Python2.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)

Python3.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()

Python2.7.6

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'they are really the sameprint type(bytearray(b'bytearray oddly does exist though'))

Python 3

print('Python', python_version())print('strings are now utf-8 \u03BCnico\u0394é!')

Python3.4.1strings are now utf-8μnicoΔé!print('Python', python_version(), end="")print('has', type(b'bytes for storing data'))

Python3.4.1 has

print('and Python', python_version(), end="")print('also has', type(bytearray(b'bytearrays')))and Python 3.4.1 also has

'note that we cannot add a string' + b'bytes for data'

---------------------------------------------------------------------------TypeError Traceback (most recent call last) in ()----> 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() 会抛出命名异常)。

importtimeit

n= 10000

deftest_range(n):return for i inrange(n):pass

deftest_xrange(n):for i inxrange(n):pass

Python 2

print 'Python', python_version()print '\ntiming range()'

%timeit test_range(n)print '\n\ntiming xrange()'

%timeit test_xrange(n)

Python2.7.6timing 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)

Python3.4.1timing range()1000 loops, best of 3: 520µs per loopprint(xrange(10))---------------------------------------------------------------------------NameError Traceback (most recent call last) in ()----> 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

defval_in_range(x, val):return val inrange(x)defval_in_xrange(x, val):return val inxrange(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)

Python3.4.1

1 loops, best of 3: 742ms per loop1000000 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)

Python2.7.7

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

下面说下 __contain__ 方法并没有加入到 Python 2.x 中的证据:

print('Python', python_version())

range.__contains__Python3.4.1

print 'Python', python_version()

range.__contains__Python2.7.7

---------------------------------------------------------------------------AttributeError Traceback (most recent call last) in ()1 print 'Python', python_version()----> 2 range.__contains__AttributeError:'builtin_function_or_method' object has no attribute '__contains__'

print 'Python', python_version()

xrange.__contains__Python2.7.7

---------------------------------------------------------------------------AttributeError Traceback (most recent call last) in ()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 运行的慢一点。

deftest_while():

i=0while i < 20000:

i+= 1

return

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

Python3.4.1

100 loops, best of 3: 2.68ms per loopprint 'Python', python_version()%timeit test_while()

Python2.7.6

1000 loops, best of 3: 1.72 ms per loop

Raising exceptions

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

Python 2

print 'Python', python_version()

Python2.7.6

raise IOError, "file error"

---------------------------------------------------------------------------IOError Traceback (most recent call last) in ()----> 1 raise IOError, "file error"IOError: file errorraise IOError("file error")---------------------------------------------------------------------------IOError Traceback (most recent call last) in ()----> 1 raise IOError("file error")

IOError: file error

Python 3

print('Python', python_version())

Python3.4.1

raise IOError, "file error"File"", line 1

raise IOError, "file error"

^SyntaxError: invalid syntax

The proper way toraise an exception in Python 3:print('Python', python_version())raise IOError("file error")

Python3.4.1

---------------------------------------------------------------------------OSError Traceback (most recent call last) in ()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_NameErrorexceptNameError, err:print err, '--> our error message'Python2.7.6name'let_us_cause_a_NameError' is not defined --> our error message

Python 3

print('Python', python_version())try:

let_us_cause_a_NameErrorexceptNameError as err:print(err, '--> our error message')

Python3.4.1name'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()

Python2.7.6

'b'

Python 3

print('Python', python_version())

my_generator= (letter for letter in 'abcdefg')

next(my_generator)

Python3.4.1

'a'my_generator.next()---------------------------------------------------------------------------AttributeError Traceback (most recent call last) in ()----> 1my_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 =', iprint 'comprehension:', [i for i in range(5)]print 'after: i =', i

Python2.7.6before: i= 1comprehension: [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)

Python3.4.1before: i= 1comprehension: [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)

Python2.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))

Python3.4.1

---------------------------------------------------------------------------TypeError Traceback (most recent call last) in ()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[GCC4.0.1 (Apple Inc. build 5493)] on darwin

Type"help", "copyright", "credits" or "license" formore information.>>> my_input = input('enter a number:')

enter a number:123

>>>type(my_input)

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

enter a number:123

>>>type(my_input)

Python 3

Python 3.4.1[GCC4.2.1 (Apple Inc. build 5577)] on darwin

Type"help", "copyright", "credits" or "license" formore information.>>> my_input = input('enter a number:')

enter a number:123

>>>type(my_input)

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

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

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

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

Python 2

print 'Python', python_version()print range(3)print type(range(3))

Python2.7.6[0,1, 2]

Python 3

print('Python', python_version())print(range(3))print(type(range(3)))print(list(range(3)))

Python3.4.1range(0,3)[0,1, 2]

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

zip()

map()

filter()

dictionary's .keys() method

dictionary's .values() method

dictionary's .items() method

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值