资讯专栏INFORMATION COLUMN

Python 2.7.x 和 Python 3.x 的主要区别

clasnake / 3407人阅读

摘要:跳转到章节预览在中创建迭代对象的用法是非常流行的。循环变量和全局命名空间泄漏好消息在中循环变量不会再导致命名空间泄漏。通过解析用户的输入幸运的是,在中已经解决了把用户的输入存储为一个对象的问题。

  

注:本文的原文地址为
Key differences between Python 2.7.x and Python 3.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 的文章

future 模块

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

from __future__ import division

更多的 __future__ 模块可被导入的特性被列在下表中:

feature optional in mandatory in effect
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

(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 "", 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)/23/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) 字符串,以及一个字节类:bytebytearrays

Python 2

print "Python", python_version()
Python 2.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 same
print type(bytearray(b"bytearray oddly does exist though"))


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 
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() 会抛出命名异常)。

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 "
timing range()" 
%timeit test_range(n)

print "

timing 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("
timing 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)
 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

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


print "Python", python_version()
range.__contains__


Python 2.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__

Python 2.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 运行的慢一点。

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)
 in ()
----> 1 raise IOError, "file error"

IOError: file error
raise IOError("file error")

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

IOError: file error

Python 3

print("Python", python_version())

Python 3.4.1
raise IOError, "file error"
  File "", 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) 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_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)
 in ()
----> 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)
 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 
[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)


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

enter a number: 123

>>> type(my_input)

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)

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

如果在 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]

Python 3

print("Python", python_version())

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


Python 3.4.1
range(0, 3)

[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 的拥护者和反对者

10 awesome features of Python that you can"t use because you refuse to upgrade to Python 3

Everything you did not want to know about Unicode in Python 3

Python 3 is killing Python

Python 3 can revive Python

Python 3 is fine

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/37325.html

相关文章

  • 一篇文章入门Python生态系统

    摘要:你使用的系统自带的包管理器包索引也被称为各种源码托管服务,如,,等。通过系统自带的包管理器安装使用系统自带的包管理器安装,只需要在命令行输入相应命令,或是使用你用来安装其他应用的应用即可。 译者按:原文写于2011年末,虽然文中关于Python 3的一些说法可以说已经不成立了,但是作为一篇面向从其他语言转型到Python的程序员来说,本文对Python的生态系统还是做了较为全面的介绍...

    dadong 评论0 收藏0
  • python2python3区别

    摘要:与的区别默认编码方式是码。中输入内容分为和两个函数,前者只接受文本输入,而在中只有且统一将用户的输入存储为对象。中不再使用和后缀说明长整型。 python2与python3的区别python2默认编码方式是ascii码。(可在文件的首行:# -*- encoding:utf-8 -*...

    番茄西红柿 评论0 收藏2637
  • Python 2.xPython 3.x 区别

    摘要:官方也宣布在停止对的维护。并且在很多面试过程中,面试官都会问与的区别。的版本,常被称为,或简称。与部分地支持这种形式的语法。捕获异常的语法由改为。在中,表示八进制字面量的方式只有一种,就是。已经支援新的模组。 前言 如果你是刚接触 Python 的初学者,那你可能是直接学习 Python 3.x 版本。对于 Python 2.x 的版本是不会有所接触。官方也宣布在 2020 停止对 P...

    LittleLiByte 评论0 收藏0
  • Scrapy Demo

    摘要:用于下载网页内容,并将网页内容返回给。中间件位于引擎和下载器之间的钩子框架,主要是处理引擎与下载器之间的请求及响应。包含了在启动时进行爬取的列表。对象经过调度,执行生成对象并送回给方法一般返回实例。 Scrapy 是什么 Scrapy 是一个为了爬取网站数据,提取结构性数据而编写的应用框架。 可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。其最初是为了页面抓取 (更确切...

    VEIGHTZ 评论0 收藏0
  • 详解python2python3区别

    摘要:认为有极大的优化空间,在字符串和整形操作上可以取得很好的优化结果。的和方法返回迭代器,而之前的等函数都被废弃。python有两个主要的版本,python2 和 python3 ,但是python又不同于其他语言,向下兼容,python3是不向下兼容的,但是绝大多数组件和扩展都是基于python2的,下面就来总结一下python2和python3的区别。   1.性能  Py3.0运...

    Sourcelink 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<