python 3.0的新功能

作者

吉多·范罗苏姆

本文解释了与2.6相比,python 3.0中的新特性。python 3.0,也称为“python 3000”或“py3k”,是有史以来第一个 故意向后不相容 python版本。有比典型版本更多的更改,对所有的Python用户来说更重要。不过,在消化了这些变化之后,您会发现python实际上并没有改变那么多——大体上,我们主要是修复众所周知的烦恼和疣,并去除许多旧的拐杖。

本文并不试图提供所有新特性的完整规范,而是试图提供一个方便的概述。有关完整的详细信息,您应该参考Python3.0的文档和/或本文中引用的许多PEP。如果您想了解特定功能的完整实现和设计原理,PEPS通常比常规文档有更多的细节;但是请注意,一旦功能完全实现,PEPS通常不会保持最新。

由于时间限制,此文档没有本应的那么完整。像往常一样,对于新版本, Misc/NEWS 源发行版中的文件包含了关于每一个被更改的小东西的大量详细信息。

常见的绊脚石

如果您习惯于Python2.5,本节将列出最有可能使您陷入困境的少数更改。

视图和迭代器而不是列表

一些著名的API不再返回列表:

  • dict 方法 dict.keys()dict.items()dict.values() 返回“视图”而不是列表。例如,这不再有效: k = d.keys(); k.sort() . 使用 k = sorted(d) 相反(这也适用于Python2.5,而且效率也一样高)。

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

  • map()filter() 返回迭代器。如果您真的需要一个列表,并且输入序列的长度都是相等的,那么一个快速的解决方法就是封装 map() 在里面 list() ,例如 list(map(...)) 但更好的解决方法通常是使用列表理解(尤其是当原始代码使用 lambda 或者重写代码,使其完全不需要列表。特别棘手的是 map() 为函数的副作用调用;正确的转换是使用正则 for 循环(因为创建列表是浪费)。

    如果输入序列的长度不相等, map() 将在最短序列结束时停止。完全兼容 map() 在python 2.x中,还将序列封装在 itertools.zip_longest() ,例如 map(func, *sequences) 变成 list(map(func, itertools.zip_longest(*sequences))) .

  • range() 现在表现得像 xrange() 用于行为,但用于任意大小的值。后者已不复存在。

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

排序比较

python 3.0简化了排序比较规则:

  • 排序比较运算符 (<<=>=> )当操作数没有有意义的自然顺序时引发类型错误异常。因此,表达式 1 < ''0 > Nonelen <= len 不再有效,例如 None < None 引发 TypeError 而不是返回 False . 一个推论是,对异类列表进行排序不再有意义——所有元素都必须相互比较。请注意,这不适用于 ==!= 运算符:不同不可比类型的对象总是比较不相等。

  • builtin.sorted()list.sort() 不再接受 cmp 提供比较函数的参数。而是使用 key 参数。N.B. keyreverse 参数现在是“仅关键字”。

  • 这个 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 以获取截断行为。(后一种语法已经存在很多年了,至少从Python2.2开始是这样。)

  • 这个 sys.maxint 常量被删除,因为整数的值不再有限制。然而, sys.maxsize 可以用作大于任何实际列表或字符串索引的整数。它符合实现的“自然”整数大小,并且通常与 sys.maxint 在同一平台上的早期版本中(假设有相同的构建选项)。

  • 这个 repr() 长整数的不包括尾随 L 因此,无条件地删除该字符的代码将切掉最后一个数字。(使用) str() 取而代之的是)

  • 八进制文字不再是这种形式 0720 使用 0o720 相反。

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

关于二进制数据和Unicode的所有知识都已经改变了。

  • python 3.0使用了 text 和(二进制) data 而不是Unicode字符串和8位字符串。所有文本都是Unicode;但是 编码的 Unicode表示为二进制数据。用于保存文本的类型是 str ,用于保存数据的类型是 bytes . 与2.x情况的最大区别在于,在Python3.0中混合文本和数据的任何尝试都会引发 TypeError ,而如果在python 2.x中混合使用unicode和8位字符串,那么如果8位字符串恰好只包含7位(ascii)字节,那么它就可以工作,但是 UnicodeDecodeError 如果它包含非ASCII值。这些年来,这种特定于价值观的行为引起了无数的悲伤。

  • 由于这种理念的改变,几乎所有使用Unicode、编码或二进制数据的代码都必须改变。这种变化是更好的,就像在2.x的世界中,有许多错误与混合编码和未编码的文本有关。要在python 2.x中进行准备,请开始使用 unicode 对于所有未编码的文本,以及 str 仅用于二进制或编码数据。然后 2to3 工具将为您完成大部分工作。

  • 你不能再使用 u"..." 来表达 Unicode文本。但是,您必须使用 b"..." 来表达二进制数据。

  • 作为 strbytes 类型不能混合,必须始终在它们之间显式转换。使用 str.encode() 从…出发 strbytesbytes.decode() 从…出发 bytesstr . 您也可以使用 bytes(s, encoding=...)str(b, encoding=...) ,分别。

  • 类似于 str , the bytes 类型不可变。有一个单独的 易变的 保存缓冲二进制数据的类型, bytearray . 几乎所有接受的API bytes 也接受 bytearray . 可变API基于 collections.MutableSequence .

  • 原始字符串文本中的所有反斜杠都是逐字解释的。这意味着 '\U''\u' 原始字符串中的转义不进行特殊处理。例如, r'\u20ac' 是Python3.0中由6个字符组成的字符串,而在2.6中, ur'\u20ac' 是唯一的“欧元”字符。(当然,此更改只影响原始字符串文本;欧元字符是 '\u20ac' 在Python 3中)。

  • 内置的 basestring 抽象类型已删除。使用 str 相反。这个 strbytes 类型没有足够的共同功能来保证共享的基类。这个 2to3 工具(见下文)将替换 basestring 具有 str .

  • 作为文本文件打开的文件(仍然是 open() )始终使用编码在字符串(内存中)和字节(磁盘上)之间进行映射。二进制文件(用 b 在模式参数中)总是使用内存中的字节。这意味着,如果使用不正确的模式或编码打开一个文件,I/O可能会很大声地失败,而不是静默地生成不正确的数据。这还意味着,即使是UNIX用户在打开文件时也必须指定正确的模式(文本或二进制)。有一个依赖于平台的默认编码,在Unixy平台上可以使用 LANG 环境变量(有时还与其他特定于平台的语言环境相关的环境变量一起使用)。在许多情况下,但不是所有情况下,系统默认值都是UTF-8;您不应该指望这个默认值。任何读或写超过纯ASCII文本的应用程序都应该有一种重写编码的方法。不再需要在 codecs 模块。

  • sys.stdinsys.stdoutsys.stderr 的初始值 现在是纯Unicode文本文件(即,它们是 io.TextIOBase )要使用这些流读取和写入字节数据,需要使用 io.TextIOBase.buffer 属性。

  • 文件名作为(Unicode)字符串传递给API并从API返回。这可能会出现平台特定的问题,因为在某些平台上,文件名是任意字节字符串。(另一方面,在Windows上,文件名本机存储为Unicode。)作为解决方案,大多数API(例如 open() 以及 os 模块)接受文件名 bytes 对象和字符串,以及一些API有一种方法来请求 bytes 返回值。因此, os.listdir() 返回的列表 bytes 如果参数是 bytes 实例,以及 os.getcwdb() 将当前工作目录作为 bytes 实例。注意什么时候 os.listdir() 返回字符串列表,忽略无法正确解码的文件名,而不是引发 UnicodeError .

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

  • PEP 3138repr() 一个字符串的字符串不再转义非ASCII字符。但是,它仍然会避开Unicode标准中不可打印状态的控制字符和代码点。

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

  • PEP 3131 :标识符中现在允许使用非ASCII字母。(但是,标准库仅保留ASCII,注释中的参与者名称除外。)

  • 这个 StringIOcStringIO 模块不见了。相反,导入 io 模块及其应用 io.StringIOio.BytesIO 分别用于文本和数据。

  • 也见 Unicode WHOTO 更新了python 3.0。

语法更改概述

本节简要概述了 句法的 更改python 3.0。

新语法

  • PEP 3107 :函数参数和返回值注释。这提供了一种标准化的方法来注释函数的参数和返回值。除了可以在运行时使用 __annotations__ 属性。其目的是鼓励通过元类、修饰器或框架进行实验。

  • PEP 3102 :仅关键字参数。命名参数出现在 *args 在参数列表中 must 在调用中使用关键字语法指定。您也可以使用裸机 * 在参数列表中指示您不接受变长参数列表,但您确实有只包含关键字的参数。

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

  • PEP 3104nonlocal 语句。使用 nonlocal x 现在可以直接分配给外部(但不是全局)范围中的变量。 nonlocal 是一个新的保留字。

  • PEP 3132 :扩展ITerable解包。你现在可以写 a, b, *rest = some_sequence . 甚至 *rest, a = stuff . 这个 rest 对象始终是一个(可能是空的)列表;右侧可以是任何一个iterable。例子::

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

    这套 a0b4rest[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() .

  • 字节文本是以前导字符引入的 bB ,有一个新的对应的内置函数, bytes() .

语法改变

  • PEP 3109PEP 3134 新的 raise 语句语法: raise [{expr} [from {expr}]] . 见下文。

  • aswith 现在是保留字。(实际上,从2.6开始。)

  • TrueFalseNone 是保留字。(2.6)部分强制执行 None 已经有了。)

  • 从变化 except excvarexcept 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() 构造函数,尤其是循环控制变量不再泄漏到周围的范围中。

  • 这个 省略 (... )可以在任何地方用作原子表达式。(以前只允许切片)另外,它 must 现在拼写为 ... . (以前也可以拼写为 . . . 只是语法上的意外。)

删除语法

  • PEP 3113 :t已移除元组参数解包。你不能再写了 def foo(a, (b, c)): ... . 使用 def foo(a, b_c): b, c = b_c 相反。

  • 删除的背景(使用 repr() 相反)。

  • 弃用 <> (使用) != 相反)。

  • 删除的关键字: exec() 不再是关键字;它仍然是一个函数。(幸运的是,函数语法在2.x中也被接受。)还要注意 exec() 不再采用流参数;而不是 exec(f) 你可以用 exec(f.read()) .

  • 整数文本不再支持尾随 lL .

  • 字符串文本不再支持前导 uU .

  • 这个 from 模块 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 是对库的主要更改的引用。以下是Capsules评论:

  • 许多旧模块被移除。一些,像 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

    温雷格

    ConfigParser

    配置分析器

    copy_reg

    复印件

    排队

    队列

    SocketServer

    socketserver

    标记库

    _markupbase

    再PR

    瑞普利布

    test.test_support

    test.support

  • python 2.x中的一个常见模式是使用纯python实现一个模块的一个版本,可选的加速版本作为C扩展实现;例如, picklecPickle . 这就增加了导入加速版本的负担,并使这些模块的每个用户都回到纯Python版本上。在Python3.0中,加速版本被认为是纯Python版本的实现细节。用户应始终导入标准版本,该版本尝试导入加速版本并返回纯Python版本。这个 pickle / cPickle 两人接受了这种治疗。这个 profile 模块在3.1的列表中。这个 StringIO 模块已转换为 io 模块。

  • 一些相关模块被分组成包,通常子模块的名称被简化。产生的新软件包包括:

    • dbm (anydbmdbhashdbmdumbdbmgdbmwhichdb

    • html (HTMLParserhtmlentitydefs

    • http (httplibBaseHTTPServerCGIHTTPServerSimpleHTTPServerCookiecookielib

    • tkinter (全部) Tkinter -相关模块,除了 turtle )的目标受众 turtle 真的不在乎 tkinter . 另请注意,从python 2.6开始, turtle 已经大大增强了。

    • urllib (urlliburllib2urlparserobotparse

    • xmlrpc (xmlrpclibDocXMLRPCServerSimpleXMLRPCServer

对标准库模块的一些其他更改,未包含在 PEP 3108

  • 被杀死的 sets . 使用内置 set() 类。

  • 清理 sys 模块:移除 sys.exitfunc()sys.exc_clear()sys.exc_typesys.exc_valuesys.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() 应用程序编程接口。

  • 这个 new 模块消失了。

  • 功能 os.tmpnam()os.tempnam()os.tmpfile() 已被移除以支持 tempfile 模块。

  • 这个 tokenize 模块已更改为使用字节。现在主要的入口点是 tokenize.tokenize() ,而不是生成令牌。

  • string.letters 和它的朋友们 (string.lowercasestring.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仍然允许引发经典类,并且对可以捕获的内容没有任何限制。)因此,字符串异常最终是真正的和彻底的死亡。

  • 几乎所有的异常都应该从 ExceptionBaseException 应仅用作只应在顶层处理的异常的基类,例如 SystemExitKeyboardInterrupt .除后一类之外,处理所有异常的推荐习惯用法是 except Exception .

  • StandardError 被移除。

  • 异常不再表现为序列。使用 args 改为属性。

  • PEP 3109 :引发异常。你现在必须使用 raise {Exception}({args}) 而不是 raise {Exception}, {args} . 此外,您不能再显式地指定回溯;相反,如果 have 为此,您可以直接将 __traceback__ 属性(见下文)。

  • PEP 3110 :捕获异常。你现在必须使用 except {SomeException} as {variable} 而不是 except {SomeException}, {variable} . 此外, 变量except 块是左边的。

  • PEP 3134 :异常链接。有两种情况:隐式链接和显式链接。当在 exceptfinally 处理程序块。这通常是由于处理程序块中的错误造成的;我们称之为 第二的 例外。在这种情况下,原始异常(正在处理的异常)保存为 __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_closurefunc_codefunc_defaultsfunc_dictfunc_docfunc_globalsfunc_name 已重命名为 __closure____code____defaults____dict____doc____globals____name__ ,分别。

  • __nonzero__() 现在是 __bool__() .

Builtins

  • PEP 3135 新的 super() . 现在可以调用 super() 不带参数和(假设这是在 class 语句)将自动选择正确的类和实例。有了参数, super() 没有变化。

  • PEP 3111raw_input() 重命名为 input() . 也就是说,新的 input() 函数从中读取行 sys.stdin 并返回去掉尾随换行符的值。它提出 EOFError 如果输入过早终止。了解 input() 使用 eval(input()) .

  • 新的内置功能 next() 添加以调用 __next__() 对象上的方法。

  • 这个 round() 函数舍入策略和返回类型已更改。精确的一半情况现在四舍五入到最接近的偶数结果,而不是从零开始。(例如, round(2.5) 现在回报 2 而不是 3round(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 模块。

  • 弃用 reduce() . 使用 functools.reduce() 如果你真的需要它;但是,99%的时候 for 循环更可读。

  • 弃用 reload() . 使用 imp.reload() .

  • 弃用。 dict.has_key() --使用 in 而不是操作员。

构建和C API更改

由于时间限制,以下是 very 对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 .

  • 弃用 METH_OLDARGSWITH_CYCLE_GC 从C API。

性能

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 源代码树上的源到源转换器。(见 2to 3-自动python 2到3代码转换 有关此工具的更多信息。)在python 3.0下运行转换结果。手动修复所有剩余问题,修复问题,直到所有测试再次通过。

不建议尝试编写在python 2.6和3.0下运行不变的源代码;您必须使用非常扭曲的编码样式,例如避免 print 语句、元类等等。如果您维护的库需要同时支持python 2.6和python 3.0,那么最好的方法是通过编辑源代码的2.6版本并运行 2to3 再次转换,而不是编辑源代码的3.0版本。

要将C扩展移植到python 3.0,请参见 将扩展模块移植到python 3 .