Python 3.0 有什么新变化

作者:

Guido van Rossum

本文介绍 Python 3.0 与 2.6 相比的新特性。 Python 3.0 也被称为 "Python 3000" 或 "Py3K",是有史以来第一个 有意向下不兼容 的 Python 版本。 Python 3.0 于 2008 年 12 月 3 日发布。 与一般的发布版本相比,Python 3.0 有更多的变化,而且对所有 Python 用户都很重要。 不过,在理解了这些改动之后,您会发现 Python 其实并没有太大的变化 -- 总的来说,我们主要是修复了一些众所周知的问题和缺陷,并删除了许多旧的垃圾。

本文并不试图提供所有新特性的完整规范,而是试图提供一个方便的概述。 要了解完整的细节,您应该参考 Python 3.0 的文档和/或文中引用的许多 PEP。 如果您想了解某个特性的完整实现和设计原理,PEP 通常比常规文档有更多的细节;但要注意的是,一旦某个特性被完全实现,PEP 通常不会保持更新。

由于时间有限,本文档不够完整。 对于新发布的版本,源代码发行版中的 Misc/NEWS 文件总是包含大量关于每一个细小改动的详细信息。

常见的绊脚石

本节列出了在你已习惯了 Python 2.5 的情况下最有可能让你感到困惑的几处更改。

用视图和迭代器取代列表

某些知名的 API 将不再返回列表:

  • dict 方法 dict.keys()、dict.items() 和 dict.values() 返回 “视图” 而不是列表。 例如,这个写法不再有效: k = d.keys(); k.sort()。 请使用 k = sorted(d) 代替(这在 Python 2.5 中也有效,而且同样高效)。

  • 此外,dict.iterkeys(), dict.iteritems() 和 dict.itervalues() 等方法将不再被支持。

  • map() 和 filter() 均返回迭代器。 如果你确实需要一个列表并且所有输入序列的长度相等,简单的解决办法是将 map() 包装在 list() 中,例如 list(map(...)),但更好的办法通常是使用列表推导式(特别是当原始代码使用了 lambda 的时候),或是重写代码使得它完全不需要列表。 特别棘手的是为了函数的副作用而调用 map();正确的转换方式是使用一个常规的 for 循环(因为创建列表会浪费资源)。

    如果输入序列的长度不相等,map() 将在最短序列的终点停止。 为了与 Python 2.x 中的 map() 完全兼容,也可将序列包装在 itertools.zip_longest() 中,例如将 map(func, *sequences) 变成 list(map(func, itertools.zip_longest(*sequences)))。

  • 现在 range() 的行为与过去 xrange() 的行为类似,区别在于它能处理任意大小的值。 后者已不复存在。

  • zip() 现在将返回一个迭代器。

排序比较

Python 3.0 简化了排序比较的规则:

  • 当操作数不存在有意义的自然排序时,排序比较操作符 (<, <=, >=, >) 会引发 TypeError 异常。 因此,像 1 < '', 0 > None 或 len <= len 这样的表达式不再有效,例如 None < None 会引发 TypeError 而不是返回 False。 由此推论,对异构列表进行排序不再有意义 —— 所有元素必须相互可比。 请注意,这不适用于 == 和 != 操作符:不同的不可比类型的对象总是互不相等的。

  • sorted() 和 list.sort() 不再接受提供比较函数的 cmp 参数。 请改用 key 参数。 注意 key 和 reverse 参数现在都是“仅限关键字”参数。

  • cmp() 函数应视为已不复存在,而 __cmp__() 特殊方法不再受支持。 请使用 __lt__() 进行排序,并根据需要使用 __eq__() 与 __hash__(),以及其他富比较操作。 (如果你确实需要 cmp() 的功能,你可以使用表达式 (a > b) - (a < b) 作为 cmp(a, b) 的等价形式。)

整数

  • PEP 237: 在实质上,long 已改名为 int。 也就是说,只存在一种内置整数类型,即 int;但其行为与旧的 long 类型极其相似。

  • PEP 238: 像 1/2 这样的表达式将返回一个浮点数。 请使用 1//2 来得到取整的行为。 (后面这种语法已存在多年,至少从 Python 2.2 起就有了。)

  • sys.maxint 常量已被移除,因为整数的值不再有任何限制。 不过,sys.maxsize 也可被用作大于任何实际列表或字符串索引的整数。 它与具体实现的“自然”整数大小保持一致并且通常与同一平台上之前发布版中的 sys.maxint 相同(假定使用相同的构建选项)。

  • 长整数的 repr() 不再包括尾部的 L,因此无条件地删除该字符的代码会删除最后一位数字。 (请使用 str() 代替。)

  • 八进制数字面值不再是 0720 的形式;而是改用 0o720 的形式。

文本与数据而不是 Unicode 与 8 比特位

你对二进制数据和 Unicode 的所有认知都已改变。

  • Python 3.0 使用 文本 和 (二进制) 数据 等概念来替代 Unicode 字符串和 8 位字符串。 所有文本均使用 Unicode;不过 已编码 Unicode 是以二进制数据来表示的。 用于存放文本的类型是 str,用于存放数据的类型是 bytes。 与 2.x 场景的最大区别是在 Python 3.0 中任何混用文本和数据的尝试都将引发 TypeError,而当你在 Python 2.x 中混用 Unicode 和 8 位字符串时,如果 8 位字符串恰好仅包含 7 位 (ASCII) 字节数据那就没有问题,但是如果包含非 ASCII 值则将引发 UnicodeDecodeError。 这种依赖于特定值的行为多年来造成了无数的苦恼。

  • 作为此项设计哲学方面的修改造成的影响,几乎所有使用 Unicode、编码格式或二进制数据的代码都很有可能必须被修改。 这项改变是有益的,因为在 2.x 世界中存在着无数涉及混用已编码和未编码文本的程序缺陷。 要在 Python 2.x 中做好准备,请使用 unicode 表示所有未编码文本,只对二进制或已编码数据使用 str。 这样 2to3 工具将为你完成大部分工作。

  • 你不能再使用 u"..." 字面值来表示 Unicode 文本。 不过,你必须使用 b"..." 字面值来表示二进制数据。

  • 由于 str 和 bytes 类型无法混用,你必须始终在它们之间执行显式转换。 使用 str.encode() 将 str 转为 bytes,并使用 bytes.decode() 将 bytes 转为 str。 你也可以分别使用 bytes(s, encoding=...) 和 str(b, encoding=...)。

  • 与 str 一样,bytes 类型是不可变的。 还有一个单独的 可变 类型用于保存带缓冲的二进制数据,即 bytearray。 几乎所有接受 bytes 的 API 也都接受 bytearray。 这个可变 API 是基于 collections.MutableSequence。

  • 原始字符串字面值中的所有反斜线均按字面解释。 这意味着原始字符串中的 '\U' 和 '\u' 转义符不会被特殊处理。 例如,在 Python 3.0 中,r'\u20ac' 是一个包含 6 个字符的字符串,而在 2.6 中,ur'\u20ac' 是一个 “欧元” 字符。 (当然,这种变化只影响原始字符串字面值;在 Python 3.0 中,欧元字符是 '\u20ac'。)

  • 内置的 basestring 抽象类型已被移除。 请改用 str。 str 和 bytes 类型在功能上没有足够的共通性因此不需要有共享的基类。 2to3 工具(见下文)会将所有 basestring 都替换为 str。

  • 作为文本文件打开的文件(仍然是 open() 的默认模式)总是会使用一个编码格式在(内存中的)字符串和(磁盘中的)字节串之间建立映射。 二进制文件(将 mode 参数设为 b 来打开)在内存中总是会使用字节串。 这意味着如果一个文件是使用不正确的模式或编码格式打开的,I/O 操作很可能会报告失败,而不是静默地产生不正确的数据。 这也意味着即使是 Unix 用户在打开文件时也必须指定正确的模式(文本或二进制)。 存在一个依赖于具体平台的默认编码格式,在类 Unix 平台上可以通过 LANG 环境变量来设置(有时也会使用其他一些平台专属的语言区域相关的环境变量)。 在多数情况下,系统默认使用 UTF-8,但并非全都如此;你绝不应该依赖这个默认值。 任何读写超出纯 ASCII 文本范围的内容的应用程序都应该提供重写编码格式的选项。 现在已不再需要使用 codecs 模块中可感知编码格式的流。

  • sys.stdin、sys.stdout 和 sys.stderr 的初始值现在是仅 Unicode 的文本文件(即它们是 io.TextIOBase 的实例)。 要使用这些数据流读写字节数据,需要使用它们的 io.TextIOBase.buffer 属性。

  • 文件名是以(Unicode)字符串的形式传给 API 并返回的。 这可能产生特定平台专属的问题因为在某些平台上文件名强制使用字节串。 (另一方面,在 Windows 上文件名则原生存储为 Unicode。) 为绕过此问题,多数接受文件名的 API(例如 open() 和 os 模块中的许多函数)都同时接受 bytes 对象和字符串,而少数 API 会发出要求 bytes 返回值的提示。 因而,当参数为 bytes 的实例时 os.listdir() 会返回由 bytes 实例组成的列表,os.getcwdb() 则会将当前工作目录作为 bytes 实例返回。 请注意当 os.listdir() 返回字符串的列表时,无法被正确解码的文件名会被忽略而不是引发 UnicodeError。

  • 当系统提供的字节无法使用默认编码进行解释时,一些系统 API,如 os.environ 和 sys.argv,也会出现问题。 最好的办法可能是设置 LANG 变量并重新运行程序。

  • PEP 3138: 字符串的 repr() 将不再转义非 ASCII 字符。 不过,它仍然会转义控制字符和在 Unicode 标准中具有不可打印状态的码位。

  • PEP 3120:现在默认的源码编码格式是UTF-8。

  • PEP 3131: 现在允许在标识符中使用非 ASCII 字符(不过,标准库仍然只使用 ASCII 字符,注释中的贡献者名字除外)。

  • StringIO 和 cStringIO 模块已被去除。 作为替代,请导入 io 模块并分别为文本和数据使用 io.StringIO 或 io.BytesIO。

  • 另请参阅 Unicode 指南,其内容已针对 Python 3.0 进行更新。

语法变化概述

本节提供了 Python 3.0 中每个 语法 变化的简要说明。

新语法

  • PEP 3107: 函数参数和返回值标注。 这提供了一种标注函数形参和返回值的标准方式。 并没有与这种标注相关联的特殊语法而只是可以使用 __annotations__ 属性在运行时对它们进行内省。 其目的是鼓励在元类、装饰器和框架中尝试应用标注。

  • PEP 3102: 仅限关键字参数。在参数列表 *args 之后出现的命名参数 必须 在调用中使用关键字语法指定。也可以在参数列表中使用 * 来表示不接受长度可变的参数列表,但可以使用只包含关键字的参数。

  • 类定义中的基类列表后允许使用关键字参数。 这是用于指定元类的新约定(见下一节),但也可用于其他目的,只要元类支持它。

  • PEP 3104: nonlocal 语句。 现在你可以使用 nonlocal x 来允许直接赋值到一个外层(但非全局)作用域。 nonlocal 是新的保留字。

  • PEP 3132: 扩展可迭代对象解包。 你现在可以编写像 a, b, *rest = some_sequence 这样的代码。 甚至 *rest, a = stuff。 rest 对象将总是为一个(可能为空的)列表;右侧的对象可以是任意可迭代对象。 例如:

    (a, *rest, b) = range(5)
    

    这会将 a 设为 0,b 设为 4,而将 rest 设为 [1, 2, 3]。

  • 新增字典推导式: {k: v for k, v in stuff} 的含义与 dict(stuff) 相同但是更为灵活。 (对此特性的解释见 PEP 274。 :-)

  • 新增集合字面值,例如 {1, 2}。 请注意 {} 是空字典;要用 set() 表示空集合。 集合推导式也受到支持;例如 {x for x in stuff} 的含义与 set(stuff) 相同但是更为灵活。

  • 新增八进制字面值,例如 0o720 (已存在于 2.6 中)。 旧的八进制字面值 (0720) 已不复存在。

  • 新增二进制字面值,例如 0b1010 (已存在于 2.6 中),还有对应的新增内置函数 bin()。

  • 引入了带有 b 或 B 前缀的字节串字面值,还有对应的新增内置函数 bytes()。

语法变化

  • PEP 3109 和 PEP 3134: 新增 raise 语句的语法: raise [expr [from expr]]。 见下文。

  • 现在 as 和 with 是保留关键字。 (实际是从 2.6 开始。)

  • True, False 和 None 已成为保留关键字。 (2.6 已经对 None 部分强制应用限制。)

  • 将 except exc, var 改为 except exc as var。 参见 PEP 3110。

  • PEP 3115: 新的元类语法。 替换:

    class C:
        __metaclass__ = M
        ...
    

    你现在需要使用:

    class C(metaclass=M):
        ...
    

    模块级全局变量 __metaclass__ 已不再受支持。 (它是一个令默认使用新式类而无需从 object 派生每一个类的辅助工具。)

  • 列表推导式不再支持 [... for var in item1, item2, ...] 这样的语法形式。 请改用 [... for var in (item1, item2, ...)]。 还要注意列表推导式具有不同的语义:它们更像是 list() 构造器内部用于生成器表达式的语法糖,具体来说就是循环控制变量将不会再泄漏到外层作用域中。

  • ellipsis (...) 可以在任何地方作为原子表达式使用。(以前只允许在切片中使用。)另外,现在 必须 拼写为 ...。(以前也可以拼写为 . . .,这只是一个偶然的语法。)

移除的语法

  • PEP 3113: 元组形参解包已被移除。 你不能再使用 def foo(a, (b, c)): ... 的写法。 请改用 def foo(a, b_c): b, c = b_c。

  • 移除了反引号 (请改用 repr())。

  • 移除了 <> (请改用 !=)。

  • 移除的关键字: exec() 不再是一个关键字;它仍是一个函数。 (幸运的是该函数语法也在 2.x 中被接受。) 还要注意 exec() 将不再接受流作为参数;你可以将原来的 exec(f) 改为使用 exec(f.read())。

  • 整数字面值不再支持 l 或 L 后缀。

  • 字符串字面值不再支持 u 或 U 前缀。

  • from module import * 语法仅允许在模块层级使用,不再允许出现于函数内部。

  • 唯一可接受的相对导入语法为 from .[module] import name。 所有不以 . 开头的 import 形式都将被解读为绝对导入。 (PEP 328)

  • 经典类已不复存在。

已存在于 Python 2.6 中的改变

由于许多用户可能会直接从 Python 2.5 跳到 Python 3.0,因此本节提醒读者注意最初为 Python 3.0 设计但后来移植到 Python 2.6 的新特性。 如需更详细的说明请参阅 Python 2.6 有什么新变化 中的相应章节。

库的修改

由于时间有限,本文档并未完全覆盖标准库的所有变化内容。 PEP 3108 引用了对标准库的主要修改。 以下是精简版的预览:

  • 许多旧模块已被移除。 其中一些,如 gopherlib (不再有用) 和 md5 (被 hashlib 替代),已根据 PEP 4 被弃用。 其他一些是作为移除对几种平台如 Irix, BeOS 和 Mac OS 9 支持的结果而被移除的 (参见 PEP 11)。 某些模块则由于缺少使用或因为存在更好的替代而被选入 Python 3.0 的移除计划。 完整列表参见 PEP 3108。

  • bsddb3 软件包被移除是因为随着时间的推移它存在于核心标准库已被证明由于测试的不稳定性和 Berkeley DB 的发布计划是对核心开发者的重大负担。 不过,这个软件包仍在 https://www.jcea.es/programacion/pybsddb.htm 获得外部维护并继续存活。

  • 一些模块名称已被修改因为它们的旧名称不符合 PEP 8,或是出于各种其他理由。 具体列表如下:

    旧名称

    新名称

    _winreg

    winreg

    ConfigParser

    configparser

    copy_reg

    copyreg

    Queue

    queue

    SocketServer

    socketserver

    markupbase

    _markupbase

    repr

    reprlib

    test.test_support

    test.support

  • 在 Python 2.x 中的常见模式是某个模块有一个以纯 Python 实现的版本,并有一个作为 C 扩展实现的加速版本;例如,pickle 和 cPickle。 这造成每个此类模块的用户存在导入加速版本并在必要时回退到纯 Python 版本的负担。 在 Python 3.0 中,加速版本将被视为纯 Python 版本的实现细节。 用户应当总是导入标准版本,该版本会尝试导入加速版本并在必要时回退到纯 Python 版本。 pickle / cPickle 对就获得了这样的处置。 profile 模块被加入了 3.1 版的处置计划。 StringIO 模块已被转为 io 模块中的一个类。

  • 一些有关联的模块已被组织为包,通常其子模块名也得到了简化。 这样产生的新包有:

    • dbm (anydbm, dbhash, dbm, dumbdbm, gdbm, whichdb)。

    • html (HTMLParser, htmlentitydefs)。

    • http (httplib, BaseHTTPServer, CGIHTTPServer, SimpleHTTPServer, Cookie, cookielib)。

    • tkinter (所有 Tkinter 相关的模块但 turtle 除外)。 turtle 的目标用户通常并不真的关心 tkinter。 还要注意在 Python 2.6 中,turtle 的功能得到了大幅增强。

    • urllib (urllib, urllib2, urlparse, robotparse)。

    • xmlrpc (xmlrpclib, DocXMLRPCServer, SimpleXMLRPCServer)。

其他一些针对标准库模块的改变,未被 PEP 3108 覆盖:

  • 去除了 sets。 请改用内置 set() 类。

  • 清理了 sys 模块:移除 sys.exitfunc(), sys.exc_clear(), sys.exc_type, sys.exc_value, sys.exc_traceback。 (请注意 sys.last_type 等仍然保留。)

  • 清理了 array.array 类型:去除 read() 和 write() 方法;改用 fromfile() 和 tofile()。 此外,数组的 'c' 类型代码已去除 -- 请使用 'b' 表示字节数据或使用 'u' 表示 Unicode 字符。

  • 清理了 operator 模块:移除 sequenceIncludes() 和 isCallable()。

  • 清理了 thread 模块:去除 acquire_lock() 和 release_lock();改用 acquire() 和 release()。

  • 清理了 random 模块:移除 jumpahead() API。

  • new 模块已不复存在。

  • os.tmpnam(), os.tempnam() 和 os.tmpfile() 等函数已被移除并应改用 tempfile 模块。

  • tokenize 模块已被修改以适用于字节串。 主入口点现在是 tokenize.tokenize(),而不是 generate_tokens。

  • string.letters 及其同类 (string.lowercase 和 string.uppercase) 已不复存在。 请改用 string.ascii_letters 等。 (移除 string.letters 及其同类的原因在于它们具有语言区域专属的行为,对于这些被称为全局“常量”的对象来说不是好主意。)

  • 模块 __builtin__ 被重命名为 builtins (移除了下划线,添加了 's')。 大多数全局命名空间中的 __builtins__ 变量保持不变。 要修改内置对象,你应当使用 builtins,而不是 __builtins__!

PEP 3101: 字符串格式化的新方式

  • 一种针对内置字符串格式化操作的新系统替代了 % 字符串格式化运算符。 (不过,% 运算符仍然受到支持;它将在 Python 3.1 中被弃用并在今后某一时刻从语言特性中移除。) 请参阅 PEP 3101 了解详情。

对异常的修改

用于引发和捕获异常的 API 已经过清理并增加了强大的新特性:

  • PEP 352: 所有异常都必须(直接或间接地)派生自 BaseException。 这是异常层级结构的根对象。 作为推荐方式这并不是新的变化,但 必须 从 BaseException 继承是新的变化。 (Python 2.6 仍然允许引发经典类,并且不限制你能捕获的异常。) 作为此变化的结果,字符串异常终于真正彻底地死亡了。

  • 几乎所有异常实际上都应当派生自 Exception;BaseException 仅应当被用作那些仅应当在最高层级中处理的异常的基类,如 SystemExit 或 KeyboardInterrupt。 处理除了后面这一类之外的所有异常的推荐写法是使用 except Exception。

  • StandardError 已被移除。

  • 异常已不再被当作序列来处理。 而应改用 args 属性。

  • PEP 3109: 引发异常。 你现在必须使用 raise Exception(args) 而不是 raise Exception, args。 此外,你不再可以显式地指定回溯;作为替代,如果你 必须 这样做,你可以直接赋值给 __traceback__ 属性(见下文)。

  • PEP 3110: 捕获异常。 你现在必须使用 except SomeException as variable 而不是 except SomeException, variable。 此外,variable 会在离开 except 代码块时被显式地删除。

  • PEP 3134: 异常串连。 存在两种情况:隐式串连和显式串连。 当异常在 except 或 finally 处理器代码块中被引发时将发生隐式串连。 通常发生这种情况是由于处理器代码块中存在程序缺陷;我们将其称为 二级 异常。 在这种情况下,(正在处理的)原始异常将被保存为该二级异常的 __context__ 属性。 显式串连则是由以下语法来唤起:

    raise SecondaryException() from primary_exception
    

    (这里 primary_exception 是产生一个异常对象的任何表达式,它可能是在之前被捕获的异常)。 在这种情况下,该原始异常将存储在二级异常的 __cause__ 属性中。 如果遍历 __cause__ 和 __context__ 属性链时发生了未被处理的异常则会打印回溯信息并为属性链中的每个部分打印单独的回溯信息,原始异常将位于最上面。 (Java 用户可能很了解这样的行为。)

  • PEP 3134: 异常对象现在会将其回溯信息保存为 __traceback__ 属性。 这意味着一个异常对象现在将包含从属于异常的所有信息,没有什么理由再使用 sys.exc_info() (不过后者并未被移除)。

  • 一些提示 Windows 载入扩展模块失败的异常消息得到了改进。 例如,error code 193 现在是 %1 is not a valid Win32 application。 字符串现在可处理非英语的语言区域。

其他杂项修改

运算符与特殊方法

  • 现在 != 将返回与 == 相反的结果,除非 == 是返回 NotImplemented。

  • “未绑定方法”的概念已从语言中移除。 现在当把一个方法作为类属性来引用时,你将得到一个普通函数对象。

  • __getslice__(), __setslice__() 和 __delslice__() 已被去除。 现在 a[i:j] 语法形式将被转为 a.__getitem__(slice(i, j)) (或者当用作赋值或删除的目标时,分别被转为 __setitem__() 或 __delitem__())。

  • PEP 3114: 标准的 next() 方法已被重命名为 __next__()。

  • __oct__() 和 __hex__() 特殊方法已被移除 -- 现在 oct() 和 hex() 将使用 __index__() 来将参数转换为整数。

  • 移除了对 __members__ 和 __methods__ 的支持。

  • 名为 func_X 的函数属性已被重命名为使用 __X__ 的形式,在函数属性命名空间中释放这些名称以便作为用户自定义属性。 也就是说,func_closure, func_code, func_defaults, func_dict, func_doc, func_globals, func_name 分别被重命名为 __closure__, __code__, __defaults__, __dict__, __doc__, __globals__, __name__。

  • __nonzero__() 现在为 __bool__()。

内置对象

  • PEP 3135: 新的 super()。 现在你可以不带参数地唤起 super() 这样(假定这发生在定义于 class 语句内部的常规实例方法中)将会自动选择正确的类和实例。 附带参数时,super() 的行为保持不变。

  • PEP 3111: raw_input() 已改名为 input()。 也就是说,新的 input() 函数会从 sys.stdin 读取一行并去除末尾换行符再将其返回。 如果输入提前终结则会引发 EOFError。 要获取原来 input() 的行为,请使用 eval(input())。

  • 新增内置函数 next() 用于在对象上调用 __next__() 方法。

  • round() 函数的舍入策略和返回类型已有改变。 对于两边差值相同的情况现在将会舍入到最接近的偶数结果而不是远离零值的结果。 (例如,round(2.5) 现在将返回 2 而不是 3。) 现在 round(x[, n]) 将委托给 x.__round__([n]) 而不是始终返回一个浮点数。 它通常会在附带一个参数调用时返回整数而在附带两个参数调用时返回与 x 相同类型的值。

  • 将 intern() 移至 sys.intern()。

  • 移除: apply()。 原 apply(f, args) 请改用 f(*args)。

  • 移除了 callable()。 原 callable(f) 可以改用 isinstance(f, collections.Callable)。 operator.isCallable() 函数也已不复存在。

  • 移除了 coerce()。 由于经典类已不复存在此函数也不再有用处。

  • 移除了 execfile()。 原 execfile(fn) 请改用 exec(open(fn).read())。

  • 移除了 file 类型。 请使用 open()。 当前在 io 模块中有多种不同类别的流可由 open 函数返回。

  • 移除了 reduce()。 如果你确实需要它可使用 functools.reduce();不过,在百分之 99 的情况下用显式的 for 循环会有更好的可读性。

  • 移除了 reload()。 请使用 imp.reload()。

  • 移除了 dict.has_key() -- 请改用 in 运算符。

构建和 C API 的改变

由于时间约束,下面 C API 的变化列表 非常 不完整。

  • 已放弃对某些平台的支持,包括但不限于 Mac OS 9, BeOS, RISCOS, Irix 和 Tru64。

  • PEP 3118: 新的缓冲区 API。

  • PEP 3121: 扩展模块初始化与最终化。

  • PEP 3123: 使 PyObject_HEAD 与标准 C 一致。

  • 已去除对受限执行的 C API 支持。

  • PyNumber_Coerce(), PyNumber_CoerceEx(), PyMember_Get() 和 PyMember_Set() C API 已被移除。

  • 新的 C API PyImport_ImportModuleNoBlock(),类似于 PyImport_ImportModule() 但不会因导入锁而阻塞(改为返回错误)。

  • 重命名布尔转换的 C 层级槽位和方法: nb_nonzero 现在改为 nb_bool。

  • 从 C API 中移除了 METH_OLDARGS 和 WITH_CYCLE_GC。

性能

综合而言 3.0 的改变使得 Python 3.0 运行 pystone 基准测试的速度比 Python 2.5 慢了约 10%。 其中最大的原因可能是移除了针对小整数的特别场景的处理。 虽然存在改进空间,但这将在 3.0 发布之后再进行!

移植到 Python 3.0

对于将现有 Python 2.5 或 2.6 源代码移植到 Python 3.0,最佳的策略如下:

  1. (必要前提:)先有出色的测试覆盖。

  2. 移植到 Python 2.6。 这应该不会比从 Python 2.x 到 Python 2.(x+1) 的正常移植更麻烦。 请确保所有的测试均能通过。

  3. (仍然使用 2.6:) 打开 -3 命令行开关。 这将启用针对将在 3.0 中被移除(或修改)的特性的警告。 再次运行你的测试套件,并修复你收到相关警告的代码直至不再有任何警告,并且所有的测试仍然能通过。

  4. 对你的源代码树运行 2to3 源代码翻译器。 在 Python 3.0 中运行翻译后的结果。 手动修复任何剩余的问题,一直修复到所有的测试再度通过。

不建议尝试编写可不加修改地同时运行于 Python 2.6 和 3.0 的源代码;你将不得不使用一种非常扭曲的代码风格,例如避免 print 语句、元类和许多其他特性。 如果你正在维护需要同时支持 Python 2.6 和 Python 3.0 的库,最佳做法是将上述的步骤 3 修改为编辑源代码的 2.6 版本并再次运行 2to3 翻译器,而不是修改源代码的 3.0 版本。

有关如何将 C 扩展移植到 Python 3.0,请参阅 将扩展模块移植到 Python 3。