Python 3.2 有什么新变化

作者

Raymond Hettinger(译者:wh2099 at outlook dot com)

This article explains the new features in Python 3.2 as compared to 3.1. It focuses on a few highlights and gives a few examples. For full details, see the Misc/NEWS file.

参见

PEP 392 - Python 3.2 发布计划

PEP 384: 定义稳定的ABI

过去,为一个 Python 版本所构建的扩展模块通常无法用于其他 Python 版本。 特别是在 Windows 上,每一个 Python 新特性发布版都必须重新构建想要使用的所有扩展模块。 之所以有这样的要求是因为扩展模块可以任意访问 Python 解释器的内部对象。

在 Python 3.2 中,则有了一种替代方式:扩展模块将自己约束于一个受限 API(通过定义 Py_LIMITED_API)因而不能使用许多内部对象,仅限使用一组承诺会在多个发布版中保持稳定的 API 函数。 作为其结果,在这种模式下为 3.2 构建的扩展模块也将能在 3.3、3.4 等版本中运行。 使用了内存结构体细节数据的扩展模块仍然可以被构建,但将需要为每个新特性发布版重新编译。

参见

PEP 384 - 定义稳定的ABI

PEP 由 Martin von Löwis 撰写

PEP 389: Argparse 命令行解析模块

引入了一个新的 argparse 模块用于命令行解析,以克服 optparse 的局限性,后者不支持位置参数(不仅仅是选项)、子命令、必需选项以及其他常见的选项指定和验证模式。

该模块作为一个第三方模块已在社区中取得了广泛的成功。相比其前身,argparse 模块功能更加全面,现在是处理命令行的首选模块。出于对大量依赖该模块的遗留代码的考虑,旧模块仍被保留使用。

以下是一个带注释的示例解析器,展示了诸如限制结果到一组选项、在帮助屏幕中指定 metavar、验证一个或多个位置参数是否存在以及创建一个必需选项等功能:

import argparse
parser = argparse.ArgumentParser(
            description = 'Manage servers',         # main description for help
            epilog = 'Tested on Solaris and Linux') # displayed after help
parser.add_argument('action',                       # argument name
            choices = ['deploy', 'start', 'stop'],  # three allowed values
            help = 'action on each target')         # help msg
parser.add_argument('targets',
            metavar = 'HOSTNAME',                   # var name used in help msg
            nargs = '+',                            # require one or more targets
            help = 'url for target machines')       # help msg explanation
parser.add_argument('-u', '--user',                 # -u or --user option
            required = True,                        # make it a required argument
            help = 'login as user')

在命令字符串中调用解析器的示例:

>>> cmd = 'deploy sneezy.example.com sleepy.example.com -u skycaptain'
>>> result = parser.parse_args(cmd.split())
>>> result.action
'deploy'
>>> result.targets
['sneezy.example.com', 'sleepy.example.com']
>>> result.user
'skycaptain'

解释器自动生成的帮助示例:

>>> parser.parse_args('-h'.split())

usage: manage_cloud.py [-h] -u USER
                       {deploy,start,stop} HOSTNAME [HOSTNAME ...]

Manage servers

positional arguments:
  {deploy,start,stop}   action on each target
  HOSTNAME              url for target machines

optional arguments:
  -h, --help            show this help message and exit
  -u USER, --user USER  login as user

Tested on Solaris and Linux

一个非常好的 argparse 特性是可以定义子解析器,每个子解析器拥有它们自己的参数模式和帮助显示:

import argparse
parser = argparse.ArgumentParser(prog='HELM')
subparsers = parser.add_subparsers()

parser_l = subparsers.add_parser('launch', help='Launch Control')   # first subgroup
parser_l.add_argument('-m', '--missiles', action='store_true')
parser_l.add_argument('-t', '--torpedos', action='store_true')

parser_m = subparsers.add_parser('move', help='Move Vessel',        # second subgroup
                                 aliases=('steer', 'turn'))         # equivalent names
parser_m.add_argument('-c', '--course', type=int, required=True)
parser_m.add_argument('-s', '--speed', type=int, default=0)
$ ./helm.py --help                         # top level help (launch and move)
$ ./helm.py launch --help                  # help for launch options
$ ./helm.py launch --missiles              # set missiles=True and torpedos=False
$ ./helm.py steer --course 180 --speed 5   # set movement parameters

参见

PEP 389 - 新的命令行解析模块

PEP 由 Steven Bethard 撰写

参阅 升级 optparse 代码 了解与 optparse 的差异的细节。

PEP 391: 基于字典的日志配置

The logging module provided two kinds of configuration, one style with function calls for each option or another style driven by an external file saved in a ConfigParser format. Those options did not provide the flexibility to create configurations from JSON or YAML files, nor did they support incremental configuration, which is needed for specifying logger options from a command line.

为了支持更灵活的配置方式,该模块现在提供了 logging.config.dictConfig(),用于通过普通的 Python 字典指定日志配置。配置选项包括格式化器、处理器、过滤器和日志记录器。以下是一个配置字典的工作示例:

{"version": 1,
 "formatters": {"brief": {"format": "%(levelname)-8s: %(name)-15s: %(message)s"},
                "full": {"format": "%(asctime)s %(name)-15s %(levelname)-8s %(message)s"}
                },
 "handlers": {"console": {
                   "class": "logging.StreamHandler",
                   "formatter": "brief",
                   "level": "INFO",
                   "stream": "ext://sys.stdout"},
              "console_priority": {
                   "class": "logging.StreamHandler",
                   "formatter": "full",
                   "level": "ERROR",
                   "stream": "ext://sys.stderr"}
              },
 "root": {"level": "DEBUG", "handlers": ["console", "console_priority"]}}

如果将该字典存储在一个名为 conf.json 的文件中,可以使用如下代码加载并调用它:

>>> import json, logging.config
>>> with open('conf.json') as f:
...     conf = json.load(f)
...
>>> logging.config.dictConfig(conf)
>>> logging.info("Transaction completed normally")
INFO    : root           : Transaction completed normally
>>> logging.critical("Abnormal termination")
2011-02-17 11:14:36,694 root            CRITICAL Abnormal termination

参见

PEP 391 - 基于字典的日志配置

PEP 由 Vinay Sajip 撰写

PEP 3148: concurrent.futures 模块

用于创建和管理并发性的代码正在被收集到一个新的顶级命名空间 concurrent 中。其第一个成员是一个 futures 包,该包提供了一个统一的高级接口,用于管理线程和进程。

concurrent.futures 的设计灵感来自 java.util.concurrent 包。在该模型中,一个正在运行的调用及其结果由一个 Future 对象表示,该对象抽象了线程、进程和远程过程调用共有的特性。该对象支持状态检查(运行中或已完成)、超时、取消、添加回调以及访问结果或异常。

新模块的核心功能是提供了一对执行器类,用于启动和管理调用任务。这些执行器的设计目标是简化现有并行调用工具的使用流程,它们能够帮助开发者省去以下繁琐操作:配置资源池、发起调用任务、创建结果队列、添加超时处理机制,以及限制线程、进程或远程过程调用的总数量。

理想情况下,每个应用程序应该在多个组件之间共享单个执行器,以便可以集中管理进程和线程限制。这解决了当每个组件都有自己的资源管理竞争策略时出现的设计挑战。

这两个类共享一个通用接口,包含三个方法:submit() 用于调度可调用对象并返回一个 Future 对象;map() 用于一次性调度多个异步调用;shutdown() 用于释放资源。该类是一个 上下文管理器,可以在 with 语句中使用,以确保在当前挂起的futures对象执行完毕时自动释放资源。

ThreadPoolExecutor 的一个简单示例是启动四个并行线程来复制文件:

import concurrent.futures, shutil
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as e:
    e.submit(shutil.copy, 'src1.txt', 'dest1.txt')
    e.submit(shutil.copy, 'src2.txt', 'dest2.txt')
    e.submit(shutil.copy, 'src3.txt', 'dest3.txt')
    e.submit(shutil.copy, 'src3.txt', 'dest4.txt')

参见

PEP 3148 -- futures - 异步执行指令

PEP 由 Brian Quinlan 撰写

使用线程并行 URL 读取的代码示例,展示了如何利用线程并发获取多个网页内容。

并行计算质数的代码示例,展示了 ProcessPoolExecutor 的用法。

PEP 3147: PYC 仓库目录

Python 在 .pyc 文件中缓存字节码的方案在存在多个 Python 解释器的环境中效果不佳。如果一个解释器遇到了由另一个解释器创建的缓存文件,它会重新编译源代码并覆盖缓存文件,从而失去缓存的优势。

随着 Linux 发行版普遍附带多个 Python 版本,“pyc 冲突”问题变得更加突出。这些冲突在使用 CPython 的替代品(如 Unladen Swallow)时也会出现。

为解决此问题,Python 的导入机制已进行扩展,会为每个解释器使用不同的文件名。Python 3.2、Python 3.3 和 Unladen Swallow 不再争抢同一个名为 "mymodule.pyc" 的文件,而是分别查找 "mymodule.cpython-32.pyc"、"mymodule.cpython-33.pyc" 和 "mymodule.unladen10.pyc"。此外,为避免这些新文件使源目录变得杂乱,pyc 文件现在会被收集到一个名为 "__pycache__" 的目录中,该目录存放在包目录下。

除了文件名和目标目录之外,新方案还有几个方面是程序员可见的:

  • Imported modules now have a __cached__ attribute which stores the name of the actual file that was imported:

    >>> import collections
    >>> collections.__cached__ 
    'c:/py32/lib/__pycache__/collections.cpython-32.pyc'
    
  • 针对每个解释器的唯一标签可以从 imp 模块访问:

    >>> import imp
    >>> imp.get_tag() 
    'cpython-32'
    
  • Scripts that try to deduce source filename from the imported file now need to be smarter. It is no longer sufficient to simply strip the "c" from a ".pyc" filename. Instead, use the new functions in the imp module:

    >>> imp.source_from_cache('c:/py32/lib/__pycache__/collections.cpython-32.pyc')
    'c:/py32/lib/collections.py'
    >>> imp.cache_from_source('c:/py32/lib/collections.py') 
    'c:/py32/lib/__pycache__/collections.cpython-32.pyc'
    
  • py_compilecompileall 模块已更新以反映新的命名约定和目标目录。compileall 的命令行调用有了新选项:-i 用于指定要编译的文件和目录列表,-b 使字节码文件写入其传统位置而非 __pycache__

  • The importlib.abc module has been updated with new abstract base classes for loading bytecode files. The obsolete ABCs, PyLoader and PyPycLoader, have been deprecated (instructions on how to stay Python 3.1 compatible are included with the documentation).

参见

PEP 3147 - PYC 仓库目录

PEP 由 Barry Warsaw 撰写

PEP 3149: 带有 ABI 版本标签的 .so 文件

PYC存储库目录允许多个字节码缓存文件共存。此PEP通过为共享对象文件提供一个公共目录并为每个版本提供不同的名称,实现了类似的机制。

通用目录为 "pyshared",文件名通过识别 Python 实现方式(如 CPython、PyPy、Jython 等)、主版本号和次版本号以及可选的构建标志(如 "d" 表示调试、"m" 表示 pymalloc、"u" 表示宽Unicode)来区分。对于任意包 "foo",当分发包安装时,您可能会看到这些文件:

/usr/share/pyshared/foo.cpython-32m.so
/usr/share/pyshared/foo.cpython-33md.so

对于 Python 本身,可以通过 sysconfig 模块中的函数来访问这些标签:

>>> import sysconfig
>>> sysconfig.get_config_var('SOABI')       # find the version tag
'cpython-32mu'
>>> sysconfig.get_config_var('EXT_SUFFIX')  # find the full filename extension
'.cpython-32mu.so'

参见

PEP 3149 - 带有 ABI 版本标签的 .so 文件

PEP 由 Barry Warsaw 撰写

PEP 3333: Python Web服务器网关接口v1.0.1

本信息性 PEP 阐明了 WSGI 协议如何处理字节/文本问题。挑战在于,尽管 HTTP 协议本身是基于字节的,但 Python 3 中的字符串处理最方便的方式是使用 str 类型。

该 PEP 规范区分了用于请求/响应头和元数据的所谓 原生字符串 (native strings),与用于请求和响应正文的 字节字符串 (byte strings)。

The native strings are always of type str but are restricted to code points between U+0000 through U+00FF which are translatable to bytes using Latin-1 encoding. These strings are used for the keys and values in the environment dictionary and for response headers and statuses in the start_response() function. They must follow RFC 2616 with respect to encoding. That is, they must either be ISO-8859-1 characters or use RFC 2047 MIME encoding.

对于从 Python 2 迁移 WSGI 应用程序的开发者,以下是关键点:

  • 如果应用程序在 Python 2 中已经使用字符串作为请求/响应头,则无需更改。

  • 如果应用程序对输出头进行编码或对输入头进行解码,则头需要重新编码为 Latin-1。例如,一个使用 utf-8 编码的输出头原本使用 h.encode('utf-8'),现在需要转换为字节到原生字符串,使用 h.encode('utf-8').decode('latin-1')

  • Values yielded by an application or sent using the write() method must be byte strings. The start_response() function and environ must use native strings. The two cannot be mixed.

For server implementers writing CGI-to-WSGI pathways or other CGI-style protocols, the users must to be able access the environment using native strings even though the underlying platform may have a different convention. To bridge this gap, the wsgiref module has a new function, wsgiref.handlers.read_environ() for transcoding CGI variables from os.environ into native strings and returning a new dictionary.

参见

PEP 3333 - Python Web服务器网关接口v1.0.1

PEP 由 Phillip Eby 撰写

其他语言特性修改

对Python 语言核心进行的小改动:

  • format() 函数和 str.format() 方法的字符串格式化功能为格式字符 # 新增了能力。此前,对于二进制、八进制或十六进制的整数,该字符会使输出分别带有 '0b'、'0o' 或 '0x' 前缀。现在,它还能处理浮点数、复数和 Decimal 类型,确保输出始终包含小数点——即使后续没有数字跟随。

    >>> format(20, '#o')
    '0o24'
    >>> format(12.34, '#5.0f')
    '  12.'
    

    (由 Mark Dickinson 建议,Eric Smith 在 bpo-7094 中实现。)

  • There is also a new str.format_map() method that extends the capabilities of the existing str.format() method by accepting arbitrary mapping objects. This new method makes it possible to use string formatting with any of Python's many dictionary-like objects such as defaultdict, Shelf, ConfigParser, or dbm. It is also useful with custom dict subclasses that normalize keys before look-up or that supply a __missing__() method for unknown keys:

    >>> import shelve
    >>> d = shelve.open('tmp.shl')
    >>> 'The {project_name} status is {status} as of {date}'.format_map(d)
    'The testing project status is green as of February 15, 2011'
    
    >>> class LowerCasedDict(dict):
    ...     def __getitem__(self, key):
    ...         return dict.__getitem__(self, key.lower())
    >>> lcd = LowerCasedDict(part='widgets', quantity=10)
    >>> 'There are {QUANTITY} {Part} in stock'.format_map(lcd)
    'There are 10 widgets in stock'
    
    >>> class PlaceholderDict(dict):
    ...     def __missing__(self, key):
    ...         return '<{}>'.format(key)
    >>> 'Hello {name}, welcome to {location}'.format_map(PlaceholderDict())
    'Hello <name>, welcome to <location>'
    

(由 Raymond Hettinger 提议并由 Eric Smith 在 bpo-6081 中贡献。)

  • The interpreter can now be started with a quiet option, -q, to prevent the copyright and version information from being displayed in the interactive mode. The option can be introspected using the sys.flags attribute:

    $ python -q
    >>> sys.flags
    sys.flags(debug=0, division_warning=0, inspect=0, interactive=0,
    optimize=0, dont_write_bytecode=0, no_user_site=0, no_site=0,
    ignore_environment=0, verbose=0, bytes_warning=0, quiet=1)
    

    (由 Marcin Wojdyr 在 bpo-1772833 中贡献。)

  • The hasattr() function works by calling getattr() and detecting whether an exception is raised. This technique allows it to detect methods created dynamically by __getattr__() or __getattribute__() which would otherwise be absent from the class dictionary. Formerly, hasattr would catch any exception, possibly masking genuine errors. Now, hasattr has been tightened to only catch AttributeError and let other exceptions pass through:

    >>> class A:
    ...     @property
    ...     def f(self):
    ...         return 1 // 0
    ...
    >>> a = A()
    >>> hasattr(a, 'f')
    Traceback (most recent call last):
      ...
    ZeroDivisionError: integer division or modulo by zero
    

    (由 Yury Selivanov 发现并由 Benjamin Peterson 修正;bpo-9666。)

  • 浮点数或复数的 str() 现在与它的 repr() 相同。以前,str() 形式更短,但这只会造成混淆,因此现在默认显示最短的 repr():

    >>> import math
    >>> repr(math.pi)
    '3.141592653589793'
    >>> str(math.pi)
    '3.141592653589793'
    

    (由 Mark Dickinson 提议并实现;bpo-9337。)

  • memoryview objects now have a release() method and they also now support the context management protocol. This allows timely release of any resources that were acquired when requesting a buffer from the original object.

    >>> with memoryview(b'abcdefgh') as v:
    ...     print(v.tolist())
    [97, 98, 99, 100, 101, 102, 103, 104]
    

    (由 Antoine Pitrou 添加;bpo-9757。)

  • 此前,如果名称在嵌套块中作为自由变量出现,删除局部命名空间中的名称是非法的:

    def outer(x):
        def inner():
            return x
        inner()
        del x
    

    现在允许这样做。请记住,except 子句的目标是被清除的,所以这段代码在 Python 2.6 中可以工作,但在 Python 3.1 中会引发 SyntaxError,现在又再次可以工作:

    def f():
        def print_error():
            print(e)
        try:
            something
        except Exception as e:
            print_error()
            # implicit "del e" here
    

    (参见 bpo-4617。)

  • The internal structsequence tool now creates subclasses of tuple. This means that C structures like those returned by os.stat(), time.gmtime(), and sys.version_info now work like a named tuple and now work with functions and methods that expect a tuple as an argument. This is a big step forward in making the C structures as flexible as their pure Python counterparts:

    >>> import sys
    >>> isinstance(sys.version_info, tuple)
    True
    >>> 'Version %d.%d.%d %s(%d)' % sys.version_info 
    'Version 3.2.0 final(0)'
    

    (由 Arfrever Frehtes Taifersar Arahesis 建议,Benjamin Peterson 在 bpo-8413 中实现。)

  • 现在可以使用 PYTHONWARNINGS 环境变量来更轻松地控制警告,作为在命令行中使用 -W 的替代方案:

    $ export PYTHONWARNINGS='ignore::RuntimeWarning::,once::UnicodeWarning::'
    

    (由Barry Warsaw建议,Philip Jenvey在 bpo-7301 中实现。)

  • 新增了一个警告类别: ResourceWarning。当检测到资源消耗或清理的潜在问题时会发出此警告。在正常发布版本中,该警告默认被禁用,但可以通过 warnings 模块提供的方式或通过命令行启用。

    A ResourceWarning is issued at interpreter shutdown if the gc.garbage list isn't empty, and if gc.DEBUG_UNCOLLECTABLE is set, all uncollectable objects are printed. This is meant to make the programmer aware that their code contains object finalization issues.

    当一个 文件对象 在没有显式关闭的情况下被销毁时,也会发出 ResourceWarning。尽管此类对象的析构函数确保关闭底层的操作系统资源(通常是文件描述符),但对象释放的延迟可能导致各种问题,特别是在 Windows 系统下。以下是通过命令行启用该警告的示例:

    $ python -q -Wdefault
    >>> f = open("foo", "wb")
    >>> del f
    __main__:1: ResourceWarning: unclosed file <_io.BufferedWriter name='foo'>
    

    (由 Antoine Pitrou 和 Georg Brandl 在 bpo-10093bpo-477863 中添加。)

  • range objects now support index and count methods. This is part of an effort to make more objects fully implement the collections.Sequence abstract base class. As a result, the language will have a more uniform API. In addition, range objects now support slicing and negative indices, even with values larger than sys.maxsize. This makes range more interoperable with lists:

    >>> range(0, 100, 2).count(10)
    1
    >>> range(0, 100, 2).index(10)
    5
    >>> range(0, 100, 2)[5]
    10
    >>> range(0, 100, 2)[0:5]
    range(0, 10, 2)
    

    (由 Daniel Stutzbach 在 bpo-9213 中贡献,由 Alexander Belopolsky 在 bpo-2690 中贡献,由 Nick Coghlan 在 bpo-10889 中贡献。)

  • callable() 内置函数从 Py2.x 中恢复。它提供了一个简洁、可读的替代方案,用于在类似 isinstance(x, collections.Callable) 的表达式中使用 抽象基类

    >>> callable(max)
    True
    >>> callable(20)
    False
    

    (参见 bpo-10518。)

  • Python 的导入机制现在可以加载路径名中包含非 ASCII 字符的目录中安装的模块。这解决了一个令人烦恼的问题,即用户主目录中包含非 ASCII 字符的用户名。

(需要 Victor Stinner 在 bpo-9425 中做大量工作。)

新增,改进和弃用的模块

Python 标准库经过了大量的维护工作和质量改进。

The biggest news for Python 3.2 is that the email package, mailbox module, and nntplib modules now work correctly with the bytes/text model in Python 3. For the first time, there is correct handling of messages with mixed encodings.

在整个标准库中,对编码和文本与字节问题的关注更加细致。特别是,与操作系统的交互现在能够更好地使用 Windows MBCS 编码、区域感知编码或 UTF-8 交换非 ASCII 数据。

另一个重要的改进是大幅提升了 SSL 连接和安全证书的支持。

此外,更多的类现在实现了 上下文管理器,以支持使用 with 语句进行方便且可靠的资源清理。

email

Python 3 中 email 包的可用性已基本由 R. David Murray 的极大努力修复。问题在于电子邮件通常以 bytes 而不是 str 文本的形式读取和存储,并且单个电子邮件中可能包含多种编码。因此,必须扩展电子邮件包以解析和生成字节格式的电子邮件消息。

  • 新函数 message_from_bytes()message_from_binary_file(),以及新类 BytesFeedParserBytesParser 允许将二进制消息数据解析为模型对象。

  • 给定模型的字节输入,get_payload() 默认将解码具有 Content-Transfer-Encoding8bit 的消息正文,使用 MIME 头中指定的字符集,并返回结果字符串。

  • 给定模型的字节输入,Generator 将把具有 Content-Transfer-Encoding8bit 的消息正文转换为具有 7bitContent-Transfer-Encoding

    包含未编码的非 ASCII 字节的邮件头,将被视为使用 unknown-8bit 字符集按照 RFC 2047 标准进行编码。

  • 一个新的类 BytesGenerator 生成字节输出,保留输入中未更改的任何非 ASCII 数据,包括具有 Content-Transfer-Encoding8bit 的消息正文。

  • smtplibSMTP 类现在接受字节字符串作为 sendmail() 方法的 msg 参数,并且一个新的方法 send_message() 接受一个 Message 对象,并可以可选地从对象中直接获取 from_addrto_addrs 地址。

(由 R. David Murray 在 bpo-4661bpo-10321 中提议并实现。)

elementtree

xml.etree.ElementTree 包及其对应的 xml.etree.cElementTree 已更新至 1.3 版。

新增了几个有用的函数和方法:

两个方法被弃用:

  • xml.etree.ElementTree.getchildren()list(elem) 替代。

  • xml.etree.ElementTree.getiterator()Element.iter 替代。

有关更新的详细信息,请参阅 Fredrik Lundh 网站上的 Introducing ElementTree

(由 Florent Xicluna 和 Fredrik Lundh 在 bpo-6472 中贡献。)

functools

  • functools 模块包含一个新的装饰器用于缓存函数调用。functools.lru_cache() 可以在预期结果相同的情况下,保存对外部资源的重复查询。

    例如,向数据库查询函数添加缓存装饰器可以节省热门搜索的数据库访问:

    >>> import functools
    >>> @functools.lru_cache(maxsize=300)
    ... def get_phone_number(name):
    ...     c = conn.cursor()
    ...     c.execute('SELECT phonenumber FROM phonelist WHERE name=?', (name,))
    ...     return c.fetchone()[0]
    
    >>> for name in user_requests:        
    ...     get_phone_number(name)        # cached lookup
    

    为了帮助选择有效的缓存大小,包装函数被用于跟踪缓存统计信息:

    >>> get_phone_number.cache_info()     
    CacheInfo(hits=4805, misses=980, maxsize=300, currsize=300)
    

    如果 phonelist 表被更新,过时的缓存内容可以通过以下方式清除:

    >>> get_phone_number.cache_clear()
    

    (Contributed by Raymond Hettinger and incorporating design ideas from Jim Baker, Miki Tebeka, and Nick Coghlan; see recipe 498245, recipe 577479, bpo-10586, and bpo-10593.)

  • The functools.wraps() decorator now adds a __wrapped__ attribute pointing to the original callable function. This allows wrapped functions to be introspected. It also copies __annotations__ if defined. And now it also gracefully skips over missing attributes such as __doc__ which might not be defined for the wrapped callable.

    在上面的例子中,可以通过恢复原始函数来移除缓存:

    >>> get_phone_number = get_phone_number.__wrapped__    # uncached function
    

    (由 Nick Coghlan 和 Terrence Cole 在 bpo-9567, bpo-3445bpo-8814 中贡献。)

  • 为帮助编写具有丰富比较方法的类,新增的装饰器 functools.total_ordering() 将使用现有的相等和不相等方法来填充其余的方法。

    例如,提供 __eq__ and __lt__ 将启用 total_ordering() 来填充 __le__, __gt____ge__:

    @total_ordering
    class Student:
        def __eq__(self, other):
            return ((self.lastname.lower(), self.firstname.lower()) ==
                    (other.lastname.lower(), other.firstname.lower()))
    
        def __lt__(self, other):
            return ((self.lastname.lower(), self.firstname.lower()) <
                    (other.lastname.lower(), other.firstname.lower()))
    

    使用 total_ordering 装饰器时,将会自动填充其余的比较方法。

    (由 Raymond Hettinger 贡献。)

  • 为帮助移植 Python 2 程序,functools.cmp_to_key() 函数可将旧式的比较函数转换为新式的 key function:

    >>> # locale-aware sort order
    >>> sorted(iterable, key=cmp_to_key(locale.strcoll)) 
    

    有关排序示例和简短的排序教程,请参阅 排序的技术 教程。

    (由 Raymond Hettinger 贡献。)

itertools

  • itertools 模块有一个新的 accumulate() 函数,该函数模仿 APL 的 scan 运算符和 Numpy 的 accumulate 函数:

    >>> from itertools import accumulate
    >>> list(accumulate([8, 2, 50]))
    [8, 10, 60]
    
    >>> prob_dist = [0.1, 0.4, 0.2, 0.3]
    >>> list(accumulate(prob_dist))      # cumulative probability distribution
    [0.1, 0.5, 0.7, 1.0]
    

    有关使用 accumulate() 的示例,请参阅 random 模块的示例

    (由 Raymond Hettinger 贡献,并融合了 Mark Dickinson 的设计建议。)

collections

  • collections.Counter 类现在支持两种形式的原地减法操作:现有的 -= 运算符实现的是 饱和减法 (即结果不会低于零),而新增的 subtract() 方法则实现常规减法 (允许结果为负值)。前者适用于 多重集 (仅包含正计数的场景),后者更适合允许负计数的使用场景。

    >>> from collections import Counter
    >>> tally = Counter(dogs=5, cats=3)
    >>> tally -= Counter(dogs=2, cats=8)    # saturating subtraction
    >>> tally
    Counter({'dogs': 3})
    
    >>> tally = Counter(dogs=5, cats=3)
    >>> tally.subtract(dogs=2, cats=8)      # regular subtraction
    >>> tally
    Counter({'dogs': 3, 'cats': -5})
    

    (由 Raymond Hettinger 贡献。)

  • collections.OrderedDict 类有一个新方法 move_to_end(),它接受一个现有的键并将其移动到有序序列的第一个或最后一个位置。

    默认情况下,将项目移动到最后一个位置。这相当于用 od[k] = od.pop(k) 更新一个条目。

    快速移动到末尾的操作对于重新排序条目很有用。例如,有序字典可以用来跟踪访问顺序,通过将条目从最旧的更新到最近访问的。

    >>> from collections import OrderedDict
    >>> d = OrderedDict.fromkeys(['a', 'b', 'X', 'd', 'e'])
    >>> list(d)
    ['a', 'b', 'X', 'd', 'e']
    >>> d.move_to_end('X')
    >>> list(d)
    ['a', 'b', 'd', 'e', 'X']
    

    (由 Raymond Hettinger 贡献。)

  • collections.deque 类新增了两个方法 count()reverse(),使它们更易于替代 list 对象:

    >>> from collections import deque
    >>> d = deque('simsalabim')
    >>> d.count('s')
    2
    >>> d.reverse()
    >>> d
    deque(['m', 'i', 'b', 'a', 'l', 'a', 's', 'm', 'i', 's'])
    

    (由 Raymond Hettinger 贡献。)

threading

threading 模块有一个新的 Barrier 同步类,用于使多个线程等待,直到它们都达到一个共同的屏障点。屏障对于确保具有多个先决条件的任务在所有前置任务完成之前不运行非常有用。

屏障可以与任意数量的线程一起工作。这是对仅适用于两个线程的 会合点 的泛化。

作为两阶段循环屏障实现,Barrier 对象适用于循环中使用。独立的 填充排空 阶段确保所有线程在任何一个线程循环回并重新进入屏障之前都被释放(排空)。屏障在每个周期后完全重置。

使用屏障的示例:

from threading import Barrier, Thread

def get_votes(site):
    ballots = conduct_election(site)
    all_polls_closed.wait()        # do not count until all polls are closed
    totals = summarize(ballots)
    publish(site, totals)

all_polls_closed = Barrier(len(sites))
for site in sites:
    Thread(target=get_votes, args=(site,)).start()

在这个示例中,屏障强制执行一个规则,即在所有投票站关闭之前,任何投票站都不能计票。请注意,使用屏障的解决方案与使用 threading.Thread.join() 的解决方案类似,但线程在越过屏障点后仍然保持活动状态并继续工作(汇总选票)。

如果任何前置任务可能会挂起或延迟,可以创建一个带有可选 timeout 参数的屏障。然后,如果在超时期限内所有前置任务都没有到达屏障点,所有等待的线程将被释放,并引发 BrokenBarrierError 异常:

def get_votes(site):
    ballots = conduct_election(site)
    try:
        all_polls_closed.wait(timeout=midnight - time.now())
    except BrokenBarrierError:
        lockbox = seal_ballots(ballots)
        queue.put(lockbox)
    else:
        totals = summarize(ballots)
        publish(site, totals)

在这个示例中,屏障执行了一个更健壮的规则。如果某些选举站在午夜前没有完成,屏障将超时,选票将被封存并放入队列中以供后续处理。

See Barrier Synchronization Patterns for more examples of how barriers can be used in parallel computing. Also, there is a simple but thorough explanation of barriers in The Little Book of Semaphores, section 3.6.

(由 Kristján Valur Jónsson 贡献,并由 Jeffrey Yasskin 在 bpo-8777 中进行 API 审查。)

datetime 和 time

  • datetime 模块新增了一种类型 timezone,它通过返回固定的 UTC 偏移量和时区名称来实现 tzinfo 接口。这使得创建带有时区信息的 datetime 对象变得更加容易:

    >>> from datetime import datetime, timezone
    
    >>> datetime.now(timezone.utc)
    datetime.datetime(2010, 12, 8, 21, 4, 2, 923754, tzinfo=datetime.timezone.utc)
    
    >>> datetime.strptime("01/01/2000 12:00 +0000", "%m/%d/%Y %H:%M %z")
    datetime.datetime(2000, 1, 1, 12, 0, tzinfo=datetime.timezone.utc)
    
  • 此外,timedelta 对象现在可以与 float 相乘,并且可以被 floatint 对象除。同时,timedelta 对象现在可以相互除。

  • datetime.date.strftime() 方法不再限制于 1900 年之后的年份。新的支持年份范围是从 1000 年到 9999 年(含)。

  • Whenever a two-digit year is used in a time tuple, the interpretation has been governed by time.accept2dyear. The default is True which means that for a two-digit year, the century is guessed according to the POSIX rules governing the %y strptime format.

    Starting with Py3.2, use of the century guessing heuristic will emit a DeprecationWarning. Instead, it is recommended that time.accept2dyear be set to False so that large date ranges can be used without guesswork:

    >>> import time, warnings
    >>> warnings.resetwarnings()      # remove the default warning filters
    
    >>> time.accept2dyear = True      # guess whether 11 means 11 or 2011
    >>> time.asctime((11, 1, 1, 12, 34, 56, 4, 1, 0))
    Warning (from warnings module):
      ...
    DeprecationWarning: Century info guessed for a 2-digit year.
    'Fri Jan  1 12:34:56 2011'
    
    >>> time.accept2dyear = False     # use the full range of allowable dates
    >>> time.asctime((11, 1, 1, 12, 34, 56, 4, 1, 0))
    'Fri Jan  1 12:34:56 11'
    

    Several functions now have significantly expanded date ranges. When time.accept2dyear is false, the time.asctime() function will accept any year that fits in a C int, while the time.mktime() and time.strftime() functions will accept the full range supported by the corresponding operating system functions.

(由 Alexander Belopolsky 和 Victor Stinner 在 bpo-1289118, bpo-5094, bpo-6641, bpo-2706, bpo-1777412, bpo-8013bpo-10827 中贡献。)

math

math 模块基于 C99 标准增加了六个新函数。

isfinite() 函数提供了一种可靠且快速的方法来检测特殊值。它对常规数字返回 True,对 NanInfinity 返回 False

>>> from math import isfinite
>>> [isfinite(x) for x in (123, 4.56, float('Nan'), float('Inf'))]
[True, True, False, False]

expm1() 函数用于计算 e**x - 1 (其中 x 为较小数值),且不会产生因相减两个近似相等数值而导致精度损失的问题。

>>> from math import expm1
>>> expm1(0.013671875)   # more accurate way to compute e**x-1 for a small x
0.013765762467652909

erf() 函数计算概率积分或 高斯误差函数。其互补误差函数 erfc() 的计算公式为 1 - erf(x)

>>> from math import erf, erfc, sqrt
>>> erf(1.0/sqrt(2.0))   # portion of normal distribution within 1 standard deviation
0.682689492137086
>>> erfc(1.0/sqrt(2.0))  # portion of normal distribution outside 1 standard deviation
0.31731050786291404
>>> erf(1.0/sqrt(2.0)) + erfc(1.0/sqrt(2.0))
1.0

gamma() 函数是阶乘函数的连续扩展。详情请见 https://en.wikipedia.org/wiki/Gamma_function。由于该函数与阶乘相关,即使对于小的 x 值,其值也会变得很大,因此还有一个 lgamma() 函数用于计算伽马函数的自然对数:

>>> from math import gamma, lgamma
>>> gamma(7.0)           # six factorial
720.0
>>> lgamma(801.0)        # log(800 factorial)
4551.950730698041

(由 Mark Dickinson 贡献)

abc

abc 模块现在支持 abstractclassmethod()abstractstaticmethod()

这些工具使得可以定义一个要求实现特定 classmethod()staticmethod()抽象基类

class Temperature(metaclass=abc.ABCMeta):
    @abc.abstractclassmethod
    def from_fahrenheit(cls, t):
        ...
    @abc.abstractclassmethod
    def from_celsius(cls, t):
        ...

(补丁由 Daniel Urban 在 bpo-5867 中提交。)

io

io.BytesIO 类新增了一个方法 getbuffer(),其功能类似于 memoryview()。该方法会创建一个数据的可编辑视图,且不会生成数据的副本。该缓冲区支持随机访问和切片表示法,非常适合进行原地编辑操作:

>>> REC_LEN, LOC_START, LOC_LEN = 34, 7, 11

>>> def change_location(buffer, record_number, location):
...     start = record_number * REC_LEN + LOC_START
...     buffer[start: start+LOC_LEN] = location

>>> import io

>>> byte_stream = io.BytesIO(
...     b'G3805  storeroom  Main chassis    '
...     b'X7899  shipping   Reserve cog     '
...     b'L6988  receiving  Primary sprocket'
... )
>>> buffer = byte_stream.getbuffer()
>>> change_location(buffer, 1, b'warehouse  ')
>>> change_location(buffer, 0, b'showroom   ')
>>> print(byte_stream.getvalue())
b'G3805  showroom   Main chassis    '
b'X7899  warehouse  Reserve cog     '
b'L6988  receiving  Primary sprocket'

(由 Antoine Pitrou 在 bpo-5506 中贡献。)

reprlib

When writing a __repr__() method for a custom container, it is easy to forget to handle the case where a member refers back to the container itself. Python's builtin objects such as list and set handle self-reference by displaying "..." in the recursive part of the representation string.

To help write such __repr__() methods, the reprlib module has a new decorator, recursive_repr(), for detecting recursive calls to __repr__() and substituting a placeholder string instead:

>>> class MyList(list):
...     @recursive_repr()
...     def __repr__(self):
...         return '<' + '|'.join(map(repr, self)) + '>'
...
>>> m = MyList('abc')
>>> m.append(m)
>>> m.append('x')
>>> print(m)
<'a'|'b'|'c'|...|'x'>

(由 Raymond Hettinger 在 bpo-9826bpo-9840 中贡献。)

logging

除了上述基于字典的配置外,logging 包还有许多其他改进。

日志模块的文档已新增一份 基础教程、一份 高级教程 以及一份包含日志实践案例的 指南。这些文档是学习日志功能的最佳途径。

logging.basicConfig() 配置函数新增了一个 style 参数,用于支持三种不同的字符串格式化方式。该参数默认值为 "%",表示传统的 %-格式化;可设置为 "{",采用新的 str.format() 格式化风格;也可设置为 "$",使用 string.Template 提供的类 shell 风格格式化。以下三种配置方式是等效的:

>>> from logging import basicConfig
>>> basicConfig(style='%', format="%(name)s -> %(levelname)s: %(message)s")
>>> basicConfig(style='{', format="{name} -> {levelname} {message}")
>>> basicConfig(style='$', format="$name -> $levelname: $message")

If no configuration is set-up before a logging event occurs, there is now a default configuration using a StreamHandler directed to sys.stderr for events of WARNING level or higher. Formerly, an event occurring before a configuration was set-up would either raise an exception or silently drop the event depending on the value of logging.raiseExceptions. The new default handler is stored in logging.lastResort.

过滤器的使用已经简化。现在不再需要创建 Filter 对象,谓词可以是任何返回 TrueFalse 的 Python 可调用对象。

还有许多其他改进,增加了灵活性并简化了配置。请参阅模块文档,了解 Python 3.2 中所有更改的完整列表。

csv

csv 模块现在支持一个新的方言,unix_dialect,它对所有字段应用引号,并使用传统的 Unix 风格,以 '\n' 作为行终止符。注册的方言名称为 unix

csv.DictWriter 有一个新的 writeheader() 方法,用于写入初始行以记录字段名称:

>>> import csv, sys
>>> w = csv.DictWriter(sys.stdout, ['name', 'dept'], dialect='unix')
>>> w.writeheader()
"name","dept"
>>> w.writerows([
...     {'name': 'tom', 'dept': 'accounting'},
...     {'name': 'susan', 'dept': 'Salesl'}])
"tom","accounting"
"susan","sales"

(新方言由 Jay Talbot 在 bpo-5975 中建议,新方法由 Ed Abraham 在 bpo-1537721 中建议。)

contextlib

有一个新的且略显震撼的工具 ContextDecorator,它有助于创建一个既可以作为函数装饰器又可以作为 上下文管理器 的双重用途的上下文管理器。

为了方便起见,这一新功能被 contextmanager() 使用,因此无需额外努力即可支持这两种角色。

基本思想是,上下文管理器和函数装饰器都可以用于前置动作和后置动作的包装器。上下文管理器使用 with 语句包装一组语句,而函数装饰器包装一个函数内的一组语句。因此,有时需要编写一个可以在任一角色中使用的前置动作或后置动作包装器。

例如,有时需要用一个日志记录器包装函数或一组语句,以跟踪进入和退出时间。与其为该任务编写一个函数装饰器和一个上下文管理器,不如使用 contextmanager() 在单一定义中提供这两种能力:

from contextlib import contextmanager
import logging

logging.basicConfig(level=logging.INFO)

@contextmanager
def track_entry_and_exit(name):
    logging.info('Entering: %s', name)
    yield
    logging.info('Exiting: %s', name)

以前,这只能用作上下文管理器:

with track_entry_and_exit('widget loader'):
    print('Some time consuming activity goes here')
    load_widget()

现在,它也可以用作装饰器:

@track_entry_and_exit('widget loader')
def activity():
    print('Some time consuming activity goes here')
    load_widget()

试图同时满足两种角色对技术有一些限制。上下文管理器通常具有返回一个可被 with 语句使用的参数的灵活性,但函数装饰器没有类似的特性。

在上面的示例中,track_entry_and_exit 上下文管理器没有一种简洁的方式来返回一个日志实例,以供封闭语句体中使用。

(由 Michael Foord 在 bpo-9110 中贡献。)

decimal 和 fractions

Mark Dickinson 设计了一个优雅且高效的方案,确保不同数值数据类型在实际值相等时具有相同的哈希值(bpo-8188):

assert hash(Fraction(3, 2)) == hash(1.5) == \
       hash(Decimal("1.5")) == hash(complex(1.5, 0))

Some of the hashing details are exposed through a new attribute, sys.hash_info, which describes the bit width of the hash value, the prime modulus, the hash values for infinity and nan, and the multiplier used for the imaginary part of a number:

>>> sys.hash_info 
sys.hash_info(width=64, modulus=2305843009213693951, inf=314159, nan=0, imag=1000003)

An early decision to limit the inter-operability of various numeric types has been relaxed. It is still unsupported (and ill-advised) to have implicit mixing in arithmetic expressions such as Decimal('1.1') + float('1.1') because the latter loses information in the process of constructing the binary float. However, since existing floating point value can be converted losslessly to either a decimal or rational representation, it makes sense to add them to the constructor and to support mixed-type comparisons.

Similar changes were made to fractions.Fraction so that the from_float() and from_decimal() methods are no longer needed (bpo-8294):

>>> from decimal import Decimal
>>> from fractions import Fraction
>>> Decimal(1.1)
Decimal('1.100000000000000088817841970012523233890533447265625')
>>> Fraction(1.1)
Fraction(2476979795053773, 2251799813685248)

Another useful change for the decimal module is that the Context.clamp attribute is now public. This is useful in creating contexts that correspond to the decimal interchange formats specified in IEEE 754 (see bpo-8540).

(由 Mark Dickinson 和 Raymond Hettinger贡献。)

ftp

ftplib.FTP 类现在支持上下文管理协议,可以无条件地捕获 socket.error 异常,并在完成操作时关闭 FTP 连接:

>>> from ftplib import FTP
>>> with FTP("ftp1.at.proftpd.org") as ftp:
        ftp.login()
        ftp.dir()

'230 Anonymous login ok, restrictions apply.'
dr-xr-xr-x   9 ftp      ftp           154 May  6 10:43 .
dr-xr-xr-x   9 ftp      ftp           154 May  6 10:43 ..
dr-xr-xr-x   5 ftp      ftp          4096 May  6 10:43 CentOS
dr-xr-xr-x   3 ftp      ftp            18 Jul 10  2008 Fedora

其他文件型对象如 mmap.mmapfileinput.input() 也有了支持自动关闭的上下文管理器:

with fileinput.input(files=('log1.txt', 'log2.txt')) as f:
    for line in f:
        process(line)

(由 Tarek Ziadé 和 Giampaolo Rodolà 在 bpo-4972 贡献,由 Georg Brandl 在 bpo-8046bpo-1286 贡献。)

FTP_TLS 类现在接受一个 context 参数,这是一个 ssl.SSLContext 对象,允许将 SSL 配置选项、证书和私钥捆绑到一个单一的(可能是长寿命的)结构体中。

(由 Giampaolo Rodolà 在 bpo-8806 中贡献。)

popen

os.popen()subprocess.Popen() 函数现在支持使用 with 语句来自动关闭文件描述符。

(由 Antoine Pitrou 和 Brian Curtin 在 bpo-7461bpo-10554 中贡献。)

select

The select module now exposes a new, constant attribute, PIPE_BUF, which gives the minimum number of bytes which are guaranteed not to block when select.select() says a pipe is ready for writing.

>>> import select
>>> select.PIPE_BUF  
512

(在 Unix 系统上可用。 由 Sébastien Sablé 在 bpo-9862 中提供补丁)

gzip 和 zipfile

gzip.GzipFile 现在实现了 io.BufferedIOBase 抽象基类 (除了 truncate())。它还有一个 peek() 方法,并支持不可 seek 的以及零填充的文件对象。

gzip 模块还增加了 compress()decompress() 函数,以便更容易地进行内存中的压缩和解压缩。请记住,文本在压缩和解压缩之前需要编码为 bytes

>>> import gzip
>>> s = 'Three shall be the number thou shalt count, '
>>> s += 'and the number of the counting shall be three'
>>> b = s.encode()                        # convert to utf-8
>>> len(b)
89
>>> c = gzip.compress(b)
>>> len(c)
77
>>> gzip.decompress(c).decode()[:42]      # decompress and convert to text
'Three shall be the number thou shalt count'

(由 Anand B. Pillai 在 bpo-3488 中贡献,由Antoine Pitrou, Nir Aides 和 Brian Curtin 在 bpo-9962bpo-1675951bpo-7471bpo-2846 中贡献。)

Also, the zipfile.ZipExtFile class was reworked internally to represent files stored inside an archive. The new implementation is significantly faster and can be wrapped in an io.BufferedReader object for more speedups. It also solves an issue where interleaved calls to read and readline gave the wrong results.

(补丁由 Nir Aides 在 bpo-7610 中提交。)

tarfile

TarFile 类现在可以用作上下文管理器。此外,其 add() 方法有一个新的选项 filter,它控制哪些文件被添加到存档中,并允许编辑文件元数据。

新的 filter 选项取代了旧的、灵活性较差的 exclude 参数,后者现已弃用。如果指定,可选的 filter 参数需要是一个 关键字参数。用户提供的过滤函数接受一个 TarInfo 对象,并返回一个更新的 TarInfo 对象,如果希望排除该文件,函数可以返回 None:

>>> import tarfile, glob

>>> def myfilter(tarinfo):
...     if tarinfo.isfile():             # only save real files
...         tarinfo.uname = 'monty'      # redact the user name
...         return tarinfo

>>> with tarfile.open(name='myarchive.tar.gz', mode='w:gz') as tf:
...     for filename in glob.glob('*.txt'):
...         tf.add(filename, filter=myfilter)
...     tf.list()
-rw-r--r-- monty/501        902 2011-01-26 17:59:11 annotations.txt
-rw-r--r-- monty/501        123 2011-01-26 17:59:11 general_questions.txt
-rw-r--r-- monty/501       3514 2011-01-26 17:59:11 prion.txt
-rw-r--r-- monty/501        124 2011-01-26 17:59:11 py_todo.txt
-rw-r--r-- monty/501       1399 2011-01-26 17:59:11 semaphore_notes.txt

(由 Tarek Ziadé 提议并由 Lars Gustäbel 在 bpo-6856 中实现。)

hashlib

hashlib 模块有两个新的常量属性,列出了在所有实现中保证存在的哈希算法和当前实现中可用的算法:

>>> import hashlib

>>> hashlib.algorithms_guaranteed
{'sha1', 'sha224', 'sha384', 'sha256', 'sha512', 'md5'}

>>> hashlib.algorithms_available
{'md2', 'SHA256', 'SHA512', 'dsaWithSHA', 'mdc2', 'SHA224', 'MD4', 'sha256',
'sha512', 'ripemd160', 'SHA1', 'MDC2', 'SHA', 'SHA384', 'MD2',
'ecdsa-with-SHA1','md4', 'md5', 'sha1', 'DSA-SHA', 'sha224',
'dsaEncryption', 'DSA', 'RIPEMD160', 'sha', 'MD5', 'sha384'}

(由 Carl Chenet 在 bpo-7418 中建议。)

ast

ast 模块提供了一个用于安全评估表达式字符串的通用工具,使用 Python 字面量语法。ast.literal_eval() 函数作为内置 eval() 函数的安全替代,后者容易被滥用。Python 3.2 将 bytesset 字面量添加到支持的类型列表中:字符串、字节、数字、元组、列表、字典、集合、布尔值和 None

>>> from ast import literal_eval

>>> request = "{'req': 3, 'func': 'pow', 'args': (2, 0.5)}"
>>> literal_eval(request)
{'args': (2, 0.5), 'req': 3, 'func': 'pow'}

>>> request = "os.system('do something harmful')"
>>> literal_eval(request)
Traceback (most recent call last):
  ...
ValueError: malformed node or string: <_ast.Call object at 0x101739a10>

(由Benjamin Peterson 和 Georg Brandl 实现。)

os

不同的操作系统对文件名和环境变量使用各种编码。os 模块提供了两个新函数,fsencode()fsdecode(),用于编码和解码文件名:

>>> import os
>>> filename = 'Sehenswürdigkeiten'
>>> os.fsencode(filename)
b'Sehensw\xc3\xbcrdigkeiten'

Some operating systems allow direct access to encoded bytes in the environment. If so, the os.supports_bytes_environ constant will be true.

为了直接访问编码的环境变量(如果可用),使用新的 os.getenvb() 函数,或者使用 os.environb,它是 os.environ 的字节版本。

(由 Victor Stinner 贡献。)

shutil

shutil.copytree() 函数增加了两个新选项:

  • ignore_dangling_symlinks:当 symlinks=False 时,函数会复制由符号链接指向的文件,而不是符号链接本身。此选项将静默处理文件不存在时引发的错误。

  • copy_function:是一个用于复制文件的可调用对象。默认使用 shutil.copy2()

(由 Tarek Ziadé 贡献。)

此外,shutil 模块现在支持对 zip 文件、未压缩的 tar 文件、gzip 压缩的 tar 文件和 bzip 压缩的 tar 文件的 归档操作。还有用于注册其他归档文件格式(如 xz 压缩的 tar 文件或自定义格式)的函数。

主要函数是 make_archive()unpack_archive()。默认情况下,两者操作当前目录(可以通过 os.chdir() 设置)及其任何子目录。归档文件名需要指定完整路径名。归档步骤是非破坏性的(原始文件保持不变)。

>>> import shutil, pprint

>>> os.chdir('mydata')  # change to the source directory
>>> f = shutil.make_archive('/var/backup/mydata',
...                         'zip')      # archive the current directory
>>> f                                   # show the name of archive
'/var/backup/mydata.zip'
>>> os.chdir('tmp')                     # change to an unpacking
>>> shutil.unpack_archive('/var/backup/mydata.zip')  # recover the data

>>> pprint.pprint(shutil.get_archive_formats())  # display known formats
[('bztar', "bzip2'ed tar-file"),
 ('gztar', "gzip'ed tar-file"),
 ('tar', 'uncompressed tar file'),
 ('zip', 'ZIP file')]

>>> shutil.register_archive_format(     # register a new archive format
...     name='xz',
...     function=xz.compress,           # callable archiving function
...     extra_args=[('level', 8)],      # arguments to the function
...     description='xz compression'
... )

(由 Tarek Ziadé 贡献。)

sqlite3

sqlite3 模块被更新至 pysqlite 2.6.0 版。 它拥有两个新功能。

(由 R. David Murray 和 Shashwat Anand 在 bpo-8845 中贡献。)

html

引入了一个新的 html 模块,其中只有一个函数 escape(),用于转义 HTML 标记中的保留字符:

>>> import html
>>> html.escape('x > 2 && x < 7')
'x &gt; 2 &amp;&amp; x &lt; 7'

socket

socket 模块有两项新改进。

  • Socket objects now have a detach() method which puts the socket into closed state without actually closing the underlying file descriptor. The latter can then be reused for other purposes. (Added by Antoine Pitrou; bpo-8524.)

  • socket.create_connection() 现在支持上下文管理协议,以无条件消耗 socket.error 异常,并在完成后关闭套接字。(由 Giampaolo Rodolà 在 bpo-9794 中贡献。)

ssl

ssl 模块添加了许多功能以满足安全(加密、认证)互联网连接的常见需求:

  • 一个新的类,SSLContext,用作持久SSL数据的容器,例如协议设置、证书、私钥和各种其他选项。它包括一个 wrap_socket() 方法,用于从SSL上下文创建SSL套接字。

  • A new function, ssl.match_hostname(), supports server identity verification for higher-level protocols by implementing the rules of HTTPS (from RFC 2818) which are also suitable for other protocols.

  • The ssl.wrap_socket() constructor function now takes a ciphers argument. The ciphers string lists the allowed encryption algorithms using the format described in the OpenSSL documentation.

  • 当与较新版本的 OpenSSL 库链接时,ssl 模块现在支持 TLS 协议的服务器名称指示(Server Name Indication,SNI)扩展。该特性允许在单个 IP 端口上为多个使用不同证书的“虚拟主机”提供服务。需要注意的是,此扩展仅在客户端模式下受支持,并且需要通过向 ssl.SSLContext.wrap_socket() 方法传递 server_hostname 参数来激活。

  • 已向 ssl 模块添加了各种选项,例如 OP_NO_SSLv2,该选项禁用了不安全且已过时的SSLv2协议。

  • 扩展现在加载了所有OpenSSL密码和摘要算法。如果某些SSL证书无法验证,它们将被报告为“未知算法”错误。

  • The version of OpenSSL being used is now accessible using the module attributes ssl.OPENSSL_VERSION (a string), ssl.OPENSSL_VERSION_INFO (a 5-tuple), and ssl.OPENSSL_VERSION_NUMBER (an integer).

(由 Antoine Pitrou 在 bpo-8850, bpo-1589, bpo-8322, bpo-5639, bpo-4870, bpo-8484bpo-8321 中贡献。)

nntp

The nntplib module has a revamped implementation with better bytes and text semantics as well as more practical APIs. These improvements break compatibility with the nntplib version in Python 3.1, which was partly dysfunctional in itself.

Support for secure connections through both implicit (using nntplib.NNTP_SSL) and explicit (using nntplib.NNTP.starttls()) TLS has also been added.

(由 Antoine Pitrou 在 bpo-9360 中贡献,由 Andrew Vant 在 bpo-1926 中贡献。)

certificates

http.client.HTTPSConnectionurllib.request.HTTPSHandlerurllib.request.urlopen() 现在接受可选参数,以允许对服务器证书进行检查,以验证一组证书颁发机构,这是公共HTTPS使用的推荐做法。

(由 Antoine Pitrou 添加,bpo-9003。)

imaplib

通过新的 imaplib.IMAP4.starttls 方法,标准IMAP4连接上增加了显式TLS支持。

(由 Lorenzo M. Catucci 和 Antoine Pitrou 在 bpo-4471 中贡献。)

http.client

http.client 模块中进行了一些小的API改进。不再支持旧式HTTP 0.9简单响应,所有类中的 strict 参数已被弃用。

HTTPConnectionHTTPSConnection 类现在有一个 source_address 参数,用于指示(主机,端口)元组,表明HTTP连接是从哪里建立的。

HTTPSConnection 增加了证书检查和HTTPS虚拟主机的支持。

连接对象上的 request() 方法允许一个可选的 body 参数,以便可以使用 文件对象 来提供请求的内容。方便的是,body 参数现在也接受一个 可迭代 对象,只要它包含一个明确的 Content-Length 头部。这个扩展接口比以前更加灵活。

为了通过代理服务器建立 HTTPS 连接,新增了一个 set_tunnel() 方法,用于设置 HTTP Connect 隧道的主机和端口。

为了与 http.server 的行为保持一致,HTTP 客户端库现在也使用 ISO-8859-1(Latin-1)编码对头部进行编码。它已经对传入的头部这样做了,所以现在传入和传出流量的行为是一致的。(参见 Armin Ronacher 在 bpo-10980 中的工作。)

unittest

unittest 模块有许多改进,支持包的测试发现、在交互式提示符下更容易进行实验、新的测试用例方法、改进的测试失败诊断消息以及更好的方法名称。

  • The command-line call python -m unittest can now accept file paths instead of module names for running specific tests (bpo-10620). The new test discovery can find tests within packages, locating any test importable from the top-level directory. The top-level directory can be specified with the -t option, a pattern for matching files with -p, and a directory to start discovery with -s:

    $ python -m unittest discover -s my_proj_dir -p _test.py
    

    (由 Michael Foord 贡献)

  • Experimentation at the interactive prompt is now easier because the unittest.case.TestCase class can now be instantiated without arguments:

    >>> from unittest import TestCase
    >>> TestCase().assertEqual(pow(2, 3), 8)
    

    (由 Michael Foord 贡献)

  • unittest 模块有两个新方法,assertWarns()assertWarnsRegex(),用于验证给定警告类型是否由被测试代码触发:

    with self.assertWarns(DeprecationWarning):
        legacy_function('XYZ')
    

    (由 Antoine Pitrou 在 bpo-9754 中贡献。)

    另一个新方法,assertCountEqual() 用于比较两个可迭代对象,以确定它们的元素计数是否相等(无论顺序如何,相同元素的出现次数是否相同):

    def test_anagram(self):
        self.assertCountEqual('algorithm', 'logarithm')
    

    (由 Raymond Hettinger 贡献。)

  • unittest 模块的主要特性之一是当测试失败时,努力生成有意义的诊断信息。在可能的情况下,失败记录会附带输出内容的差异。这对于分析失败的测试运行的日志文件特别有帮助。然而,由于差异有时可能非常庞大,因此有一个新的 maxDiff 属性用于设置显示的差异最大长度。

  • 此外,模块中的方法名称已经进行了多项清理。

    For example, assertRegex() is the new name for assertRegexpMatches() which was misnamed because the test uses re.search(), not re.match(). Other methods using regular expressions are now named using short form "Regex" in preference to "Regexp" -- this matches the names used in other unittest implementations, matches Python's old name for the re module, and it has unambiguous camel-casing.

    (由 Raymond Hettinger 贡献并由 Ezio Melotti 实现。)

  • 为了提高一致性,一些长期存在的方法别名正在被弃用,转而使用首选名称:

    旧名称

    首选名称

    assert_()

    assertTrue()

    assertEquals()

    assertEqual()

    assertNotEquals()

    assertNotEqual()

    assertAlmostEquals()

    assertAlmostEqual()

    assertNotAlmostEquals()

    assertNotAlmostEqual()

    Likewise, the TestCase.fail* methods deprecated in Python 3.1 are expected to be removed in Python 3.3. Also see the 一些已被弃用的别名 section in the unittest documentation.

    (由 Ezio Melotti 在 bpo-9424 中贡献。)

  • The assertDictContainsSubset() method was deprecated because it was misimplemented with the arguments in the wrong order. This created hard-to-debug optical illusions where tests like TestCase().assertDictContainsSubset({'a':1, 'b':2}, {'a':1}) would fail.

    (由 Raymond Hettinger 贡献。)

random

random 模块中的整数方法现在能更好地生成均匀分布。之前,它们使用 int(n*random()) 计算选择,这在 n 不是二的幂时存在轻微偏差。现在,从下一个二的幂的范围中进行多次选择,并且只有当选择落在 0 <= x < n 范围内时才保留。受影响的函数和方法包括 randrange()randint()choice()shuffle()sample()

(由 Raymond Hettinger 在 bpo-9025 中贡献。)

poplib

POP3_SSL 类现在接受一个 context 参数,这是一个 ssl.SSLContext 对象,允许将 SSL 配置选项、证书和私钥捆绑到一个单一的(可能是长期存在的)结构体中。

(由 Giampaolo Rodolà 在 bpo-8807 中贡献。)

asyncore

asyncore.dispatcher now provides a handle_accepted() method returning a (sock, addr) pair which is called when a connection has actually been established with a new remote endpoint. This is supposed to be used as a replacement for old handle_accept() and avoids the user to call accept() directly.

(由 Giampaolo Rodolà 在 bpo-6706 中贡献。)

tempfile

tempfile 模块有一个新的上下文管理器,TemporaryDirectory,它提供了临时目录的简单确定性清理:

with tempfile.TemporaryDirectory() as tmpdirname:
    print('created temporary dir:', tmpdirname)

(由 Neil Schemenauer 和 Nick Coghlan 在 bpo-5178 中贡献。)

inspect

  • inspect 模块有一个新函数 getgeneratorstate() 用来方便地标识一个生成器迭代器的当前状态:

    >>> from inspect import getgeneratorstate
    >>> def gen():
    ...     yield 'demo'
    >>> g = gen()
    >>> getgeneratorstate(g)
    'GEN_CREATED'
    >>> next(g)
    'demo'
    >>> getgeneratorstate(g)
    'GEN_SUSPENDED'
    >>> next(g, None)
    >>> getgeneratorstate(g)
    'GEN_CLOSED'
    

    (由 Rodolpho Eckhardt 和 Nick Coghlan 在 bpo-10220 中贡献。)

  • 为了支持查找而不激活动态属性,inspect 模块有一个新函数,getattr_static()。与 hasattr() 不同,这是一个真正的只读搜索,保证在搜索过程中不会改变状态:

    >>> class A:
    ...     @property
    ...     def f(self):
    ...         print('Running')
    ...         return 10
    ...
    >>> a = A()
    >>> getattr(a, 'f')
    Running
    10
    >>> inspect.getattr_static(a, 'f')
    <property object at 0x1022bd788>
    

(由 Michael Foord 贡献)

pydoc

The pydoc module now provides a much-improved Web server interface, as well as a new command-line option -b to automatically open a browser window to display that server:

$ pydoc3.2 -b

(由 Ron Adam 在 bpo-2001 中贡献。)

dis

dis 模块新增了两个用于检查代码的函数,code_info()show_code()。两者都为提供的函数、方法、源代码字符串或代码对象提供详细的代码对象信息。前者返回一个字符串,后者将其打印出来:

>>> import dis, random
>>> dis.show_code(random.choice)
Name:              choice
Filename:          /Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/random.py
Argument count:    2
Kw-only arguments: 0
Number of locals:  3
Stack size:        11
Flags:             OPTIMIZED, NEWLOCALS, NOFREE
Constants:
   0: 'Choose a random element from a non-empty sequence.'
   1: 'Cannot choose from an empty sequence'
Names:
   0: _randbelow
   1: len
   2: ValueError
   3: IndexError
Variable names:
   0: self
   1: seq
   2: i

此外,dis() 函数现在接受字符串参数,以便常用的 dis(compile(s, '', 'eval')) 可以简化为 dis(s)

>>> dis('3*x+1 if x%2==1 else x//2')
  1           0 LOAD_NAME                0 (x)
              3 LOAD_CONST               0 (2)
              6 BINARY_MODULO
              7 LOAD_CONST               1 (1)
             10 COMPARE_OP               2 (==)
             13 POP_JUMP_IF_FALSE       28
             16 LOAD_CONST               2 (3)
             19 LOAD_NAME                0 (x)
             22 BINARY_MULTIPLY
             23 LOAD_CONST               1 (1)
             26 BINARY_ADD
             27 RETURN_VALUE
        >>   28 LOAD_NAME                0 (x)
             31 LOAD_CONST               0 (2)
             34 BINARY_FLOOR_DIVIDE
             35 RETURN_VALUE

综合来看,这些改进使得探索CPython的实现方式以及亲自查看语言语法在底层的作用变得更加容易。

(由 Nick Coghlan 在 bpo-9147 中贡献。)

dbm

所有数据库模块现在都支持 get()setdefault() 方法。

(由 Ray Allen 在 bpo-9523 中建议。)

ctypes

一个新类型 ctypes.c_ssize_t 用来表示 C ssize_t 数据类型。

site

site 模块新增了三个用于报告给定 Python 安装版详细信息的函数。

>>> import site
>>> site.getsitepackages()
['/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/site-packages',
 '/Library/Frameworks/Python.framework/Versions/3.2/lib/site-python',
 '/Library/Python/3.2/site-packages']
>>> site.getuserbase()
'/Users/raymondhettinger/Library/Python/3.2'
>>> site.getusersitepackages()
'/Users/raymondhettinger/Library/Python/3.2/lib/python/site-packages'

部分 site 功能可方便地直接通过命令行访问:

$ python -m site --user-base
/Users/raymondhettinger/.local
$ python -m site --user-site
/Users/raymondhettinger/.local/lib/python3.2/site-packages

(由 Tarek Ziadé 在 bpo-6693 中贡献。)

sysconfig

新增的 sysconfig 模块使得发现依赖于不同系统平台和安装版的安装路径和配置变量更为简单直观。

该模块提供了对平台和版本信息获取函数的访问:

It also provides access to the paths and variables corresponding to one of seven named schemes used by distutils. Those include posix_prefix, posix_home, posix_user, nt, nt_user, os2, os2_home:

  • get_paths() 返回一个包含当前安装方案安装路径的字典。

  • get_config_vars() 返回一个包含平台特定变量的字典。

还有一个方便的命令行界面:

C:\Python32>python -m sysconfig
Platform: "win32"
Python version: "3.2"
Current installation scheme: "nt"

Paths:
        data = "C:\Python32"
        include = "C:\Python32\Include"
        platinclude = "C:\Python32\Include"
        platlib = "C:\Python32\Lib\site-packages"
        platstdlib = "C:\Python32\Lib"
        purelib = "C:\Python32\Lib\site-packages"
        scripts = "C:\Python32\Scripts"
        stdlib = "C:\Python32\Lib"

Variables:
        BINDIR = "C:\Python32"
        BINLIBDEST = "C:\Python32\Lib"
        EXE = ".exe"
        INCLUDEPY = "C:\Python32\Include"
        LIBDEST = "C:\Python32\Lib"
        SO = ".pyd"
        VERSION = "32"
        abiflags = ""
        base = "C:\Python32"
        exec_prefix = "C:\Python32"
        platbase = "C:\Python32"
        prefix = "C:\Python32"
        projectbase = "C:\Python32"
        py_version = "3.2"
        py_version_nodot = "32"
        py_version_short = "3.2"
        srcdir = "C:\Python32"
        userbase = "C:\Documents and Settings\Raymond\Application Data\Python"

(由TarekZiadé 移出Distutils。)

pdb

pdb 调试器模块获得了一些可用性改进:

  • pdb.py 现在有一个 -c 选项,用于执行 .pdbrc 脚本文件中给出的命令。

  • 一个 .pdbrc 脚本文件可以包含 continuenext 命令,用于继续调试。

  • The Pdb class constructor now accepts a nosigint argument.

  • 新命令:l(list)ll(long list)source 用于列出源代码。

  • 新命令:displayundisplay 用于显示或隐藏表达式值的变化。

  • 新命令:interact 用于启动一个包含当前作用域中全局和局部名称的交互式解释器。

  • 可以通过断点编号清除断点。

(由Georg Brandl, Antonio Cuni 和 Ilya Sandler 贡献。)

configparser

The configparser module was modified to improve usability and predictability of the default parser and its supported INI syntax. The old ConfigParser class was removed in favor of SafeConfigParser which has in turn been renamed to ConfigParser. Support for inline comments is now turned off by default and section or option duplicates are not allowed in a single configuration source.

配置解析器获得了一个基于映射协议的新 API:

>>> parser = ConfigParser()
>>> parser.read_string("""
... [DEFAULT]
... location = upper left
... visible = yes
... editable = no
... color = blue
...
... [main]
... title = Main Menu
... color = green
...
... [options]
... title = Options
... """)
>>> parser['main']['color']
'green'
>>> parser['main']['editable']
'no'
>>> section = parser['options']
>>> section['title']
'Options'
>>> section['title'] = 'Options (editable: %(editable)s)'
>>> section['title']
'Options (editable: no)'

新 API 是在经典 API 之上实现的,因此自定义解析器子类应能够无修改地使用它。

配置解析器接受的 INI 文件结构体现在可以自定义。用户可以指定替代的选项/值分隔符和注释前缀,更改 DEFAULT 部分的名称或切换插值语法。

支持可插拔插值,包括一个额外的插值处理程序 ExtendedInterpolation

>>> parser = ConfigParser(interpolation=ExtendedInterpolation())
>>> parser.read_dict({'buildout': {'directory': '/home/ambv/zope9'},
...                   'custom': {'prefix': '/usr/local'}})
>>> parser.read_string("""
... [buildout]
... parts =
...   zope9
...   instance
... find-links =
...   ${buildout:directory}/downloads/dist
...
... [zope9]
... recipe = plone.recipe.zope9install
... location = /opt/zope
...
... [instance]
... recipe = plone.recipe.zope9instance
... zope9-location = ${zope9:location}
... zope-conf = ${custom:prefix}/etc/zope.conf
... """)
>>> parser['buildout']['find-links']
'\n/home/ambv/zope9/downloads/dist'
>>> parser['instance']['zope-conf']
'/usr/local/etc/zope.conf'
>>> instance = parser['instance']
>>> instance['zope-conf']
'/usr/local/etc/zope.conf'
>>> instance['zope9-location']
'/opt/zope'

此外还引入了一些较小的功能特性,例如:支持在读取操作中指定编码格式、为获取函数(get-functions)指定回退值,以及直接从字典和字符串中读取数据。

(所有改变均由 Łukasz Langa 贡献。)

urllib.parse

urllib.parse 模块进行了一些可用性改进。

urlparse() 函数现在支持 IPv6 地址,如 RFC 2732 中所述:

>>> import urllib.parse
>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') 
ParseResult(scheme='http',
            netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]',
            path='/foo/',
            params='',
            query='',
            fragment='')

urldefrag() 函数现在返回一个 具名元组:

>>> r = urllib.parse.urldefrag('http://python.org/about/#target')
>>> r
DefragResult(url='http://python.org/about/', fragment='target')
>>> r[0]
'http://python.org/about/'
>>> r.fragment
'target'

此外,urlencode() 函数现在更加灵活,可以接受字符串或字节类型作为 query 参数。如果是字符串,那么 safeencodingerror 参数将被传递给 quote_plus() 进行编码:

>>> urllib.parse.urlencode([
...      ('type', 'telenovela'),
...      ('name', '¿Dónde Está Elisa?')],
...      encoding='latin-1')
'type=telenovela&name=%BFD%F3nde+Est%E1+Elisa%3F'

解析ASCII编码字节 中所述,所有 urllib.parse 函数现在都接受 ASCII 编码的字节字符串作为输入,只要它们不与普通字符串混合。如果给定 ASCII 编码的字节字符串作为参数,返回类型也将是 ASCII 编码的字节字符串:

>>> urllib.parse.urlparse(b'http://www.python.org:80/about/') 
ParseResultBytes(scheme=b'http', netloc=b'www.python.org:80',
                 path=b'/about/', params=b'', query=b'', fragment=b'')

(由 Nick Coghlan、Dan Mahn 和 Senthil Kumaran 在 bpo-2987bpo-5468bpo-9873 中提供。)

mailbox

由于 R. David Murray 的共同努力,mailbox 模块已修复以适用于 Python 3.2。挑战在于 mailbox 最初是使用文本接口设计的,但电子邮件消息最好用 bytes 表示,因为消息的不同部分可能具有不同的编码。

解决方案利用了 email 包的二进制支持来解析任意电子邮件消息。此外,解决方案还需要进行一些 API 更改。

如预期的那样,mailbox.Mailbox 对象的 add() 方法现在接受二进制输入。

StringIO 和文本文件输入已被弃用。此外,如果使用非 ASCII 字符,字符串输入将提前失败。此前它会在后续步骤处理电子邮件时失败。

还支持二进制输出。get_file() 方法现在以二进制模式返回文件(以前错误地将文件设置为文本模式)。还有一个新的 get_bytes() 方法,它返回与给定 key 对应的 bytes 消息表示。

使用旧API的 get_string() 方法仍然可以获得非二进制输出,但这种方法并不非常有用。相反,最好是从 Message 对象中提取消息,或者从二进制输入中加载它们。

(由R. David Murray贡献,Steffen Daode Nurpmeso参与努力,Victor Stinner在 bpo-9124 中提供初始补丁。)

turtledemo

The demonstration code for the turtle module was moved from the Demo directory to main library. It includes over a dozen sample scripts with lively displays. Being on sys.path, it can now be run directly from the command-line:

$ python -m turtledemo

(由Alexander Belopolsky从Demo目录移至主库,见 bpo-10199。)

多线程

  • The mechanism for serializing execution of concurrently running Python threads (generally known as the GIL or Global Interpreter Lock) has been rewritten. Among the objectives were more predictable switching intervals and reduced overhead due to lock contention and the number of ensuing system calls. The notion of a "check interval" to allow thread switches has been abandoned and replaced by an absolute duration expressed in seconds. This parameter is tunable through sys.setswitchinterval(). It currently defaults to 5 milliseconds.

    有关该实现的更多详细信息可以从 python-dev 邮件列表消息 中阅读(但需注意:该消息中提到的"优先级请求"机制并未被最终采纳)。

    (由 Antoine Pitrou 贡献。)

  • 常规和递归锁现在在其 acquire() 方法中接受一个可选的 timeout 参数。(由 Antoine Pitrou 在 bpo-7316 中贡献。)

  • 同样,threading.Semaphore.acquire() 也增加了一个 timeout 参数。(由 Torsten Landschoff 在 bpo-850728 中贡献。)

  • 在使用 Pthreads 的平台上,常规锁和递归锁的获取操作现在可以被信号中断。这意味着Python 程序在获取锁时发生死锁,可以通过反复向该进程发送 SIGINT 信号(在大多数 shell 中按下 Ctrl+C)来成功终止程序。(由 Reid Kleckner 在 bpo-8844 中贡献。)

性能优化

添加了一些小的性能提升:

  • Python 的窥孔优化器(peephole optimizer)现在能够识别诸如 x in {1, 2, 3} 这样的模式,将其判定为对常量集合的成员资格测试。优化器会将 set (集合) 重新转换为 frozenset (不可变集合) ,并存储这个预先构建的常量。

    既然速度开销已不复存在,现在可以放心地开始使用集合表示法来编写成员资格测试了。这种写法不仅语义清晰,而且执行高效:

    extension = name.rpartition('.')[2]
    if extension in {'xml', 'html', 'xhtml', 'css'}:
        handle(name)
    

    (补丁和附加测试由 Dave Malcolm 在 bpo-6690 中贡献)。

  • 使用 pickle 模块序列化和反序列化数据的速度现在快了几倍。

    (由 Alexandre Vassalotti, Antoine Pitrou 和 Unladen Swallow 团队在 bpo-9410bpo-3873 中贡献。)

  • list.sort()sorted() 中使用的 Timsort 算法 现在在有 键函数 的情况下运行更快且使用更少内存。之前,列表的每个元素都会被一个临时对象包裹,该对象记住与每个元素关联的键值。现在,键和值的两个数组并行排序。这节省了排序包装器消耗的内存,并节省了委托比较所花费的时间。

    (由 Daniel Stutzbach 在 bpo-9915 中提交补丁。)

  • JSON 解码性能得到提升,且当同一字符串被用作多个键值时内存消耗降低。此外,当 sort_keys 参数为 True 时,JSON 编码现会启用 C 语言加速模块。

    (由Antoine Pitrou 在 bpo-7451 中贡献,由 Raymond Hettinger 和 Antoine Pitrou 在 bpo-10314 中贡献。)

  • 递归锁(使用 threading.RLock() API 创建)现在受益于 C 实现,这使得它们与常规锁一样快,并且比之前的纯 Python 实现快 10 到 15 倍。

    (由 Antoine Pitrou 在 bpo-3001 中贡献。)

  • The fast-search algorithm in stringlib is now used by the split(), rsplit(), splitlines() and replace() methods on bytes, bytearray and str objects. Likewise, the algorithm is also used by rfind(), rindex(), rsplit() and rpartition().

    (由 Florent Xicluna 在 bpo-7622bpo-7462 中提交补丁。)

  • 整型转字符串操作现在改为每次处理两个"数字位",从而减少了除法和取模运算的次数。

    (由 Gawain Bolton、Mark Dickinson 和 Victor Stinner 在 bpo-6713 中提交。)

There were several other minor optimizations. Set differencing now runs faster when one operand is much larger than the other (patch by Andress Bennetts in bpo-8685). The array.repeat() method has a faster implementation (bpo-1569291 by Alexander Belopolsky). The BaseHTTPRequestHandler has more efficient buffering (bpo-3709 by Andrew Schaaf). The operator.attrgetter() function has been sped-up (bpo-10160 by Christos Georgiou). And ConfigParser loads multi-line arguments a bit faster (bpo-7113 by Łukasz Langa).

Unicode

Python has been updated to Unicode 6.0.0. The update to the standard adds over 2,000 new characters including emoji symbols which are important for mobile phones.

In addition, the updated standard has altered the character properties for two Kannada characters (U+0CF1, U+0CF2) and one New Tai Lue numeric character (U+19DA), making the former eligible for use in identifiers while disqualifying the latter. For more information, see Unicode Character Database Changes.

编解码器

添加了对 cp720 阿拉伯 DOS 编码的支持(bpo-1616979)。

MBCS 编码不再忽略错误处理程序参数。在默认的严格模式下,当遇到无法解码的字节序列时,它会引发 UnicodeDecodeError 异常;当遇到无法编码的字符时,会引发 UnicodeEncodeError 异常。

多字节字符集编解码器(MBCS codec)在解码时支持 'strict' (严格模式) 和 'ignore' (忽略模式) 两种错误处理器,在编码时则支持 'strict' (严格模式) 和 'replace' (替换模式) 。

若需模拟 Python 3.1 版本的 MBCS 编码行为,应在解码时选用 'ignore' (忽略模式) 错误处理器,而在编码时选用 'replace' (替换模式) 错误处理器。

在 Mac OS X 上,Python 使用 'utf-8' 而不是区域设置编码来解码命令行参数。

默认情况下,tarfile 在 Windows 上使用 'utf-8' 编码格式 (而不是 'mbcs') 并在所有操作系统上使用 'surrogateescape' 错误处理器。

文档

文档继续得到改进。

  • 在长篇幅的章节(如 内置函数)顶部添加了一个快速链接表。以 itertools 为例,这些链接旁边附有速查表风格的摘要表格,无需通读完整文档即可快速掌握要点、唤醒记忆。

  • 在某些情况下,纯 Python 源代码可以作为文档的有益补充,因此现在许多模块都提供了指向最新版本源代码的快速链接。例如,functools 模块文档顶部有一个快速链接,标记为:

    源代码 Lib/functools.py.

    (由 Raymond Hettinger 贡献,参见 rationale。)

  • 当前文档现包含更多实用示例与技巧指南。特别地,re 模块新增了内容详尽的正则表达式示例专章 正则表达式例子;同样地,itertools 模块也持续更新,不断增添新的迭代器工具配方 itertools 配方

  • datetime 模块现在有一个纯 Python 的辅助实现。功能没有变化。这只是为了提供一个更易读的替代实现。

    (由 Alexander Belopolsky 在 bpo-9528 中贡献。)

  • 未维护的 Demo 目录已被删除。一些演示被整合到文档中,一些被移动到 Tools/demo 目录,其他的则被完全删除。

    (由 Georg Brandl 在 bpo-7962 中贡献)

IDLE

  • 格式菜单现在有一个选项,用于通过删除尾部空格来清理源文件。

    (由 Raymond Hettinger 在 bpo-5150 中贡献。)

  • Mac OS X 上的 IDLE 现在既支持 Carbon AquaTk 也支持 Cocoa AquaTk。

    (由 Kevin Walzer, Ned Deily 和 Ronald Oussoren 在 bpo-6075 中贡献。)

代码库

In addition to the existing Subversion code repository at http://svn.python.org there is now a Mercurial repository at https://hg.python.org/.

在 3.2 版本发布后,计划将 Mercurial 作为主要仓库。这种分布式版本控制系统应使社区成员更容易创建和共享外部更改集。详见 PEP 385

要学习使用新的版本控制系统,请参阅 Quick StartGuide to Mercurial Workflows

构建和 C API 的改变

针对 Python 构建过程和 C API 的改变包括:

  • 现在 idle, pydoc2to3 脚本的安装将在 make altinstall 中附带特定版本的后缀 (bpo-10679)。

  • 访问 Unicode 数据库的 C 函数现在接受并返回完整 Unicode 范围内的字符,即使在窄 Unicode 构建中也是如此(Py_UNICODE_TOLOWER、Py_UNICODE_ISDECIMAL 等)。在 Python 中可见的区别是 unicodedata.numeric() 现在为大代码点返回正确的值,而 repr() 可能有更多字符被视为可打印。

    (由 Bupjoe Lee 报告,Amaury Forgeot D'Arc 修复;参见 bpo-5127 。)

  • 计算跳转(computed gotos)现在在支持的编译器(支持情况由配置脚本检测)上默认启用。仍可通过指定 --without-computed-gotos 选择性禁用。

    (由 Antoine Pitrou 在 bpo-9203 中贡献。)

  • 选项 --with-wctype-functions 已被移除。内置的 Unicode 数据库现在用于所有函数。

    (由 Amaury Forgeot d'Arc 在 bpo-9210 中贡献。)

  • 哈希值现在采用一种新类型 Py_hash_t 的值,该类型被定义为与指针具有相同的大小。此前,哈希值的类型为 long,在某些 64 位操作系统上,long 仍然只有 32 位长。得益于这一改进,setdict 现在可以在使用 64 位指针的构建版本中容纳超过 2**32 个条目(此前,虽然它们能够增长到该规模,但其性能会急剧下降)。

    (由 Raymond Hettinger 建议,Benjamin Peterson 实现;参见 bpo-9778。)

  • A new macro Py_VA_COPY copies the state of the variable argument list. It is equivalent to C99 va_copy but available on all Python platforms (bpo-2443).

  • A new C API function PySys_SetArgvEx() allows an embedded interpreter to set sys.argv without also modifying sys.path (bpo-5753).

  • PyEval_CallObject is now only available in macro form. The function declaration, which was kept for backwards compatibility reasons, is now removed -- the macro was introduced in 1997 (bpo-8276).

  • 新增函数 PyLong_AsLongLongAndOverflow(),它与 PyLong_AsLongAndOverflow() 类似。它们都用于将 Python int 转换为本地固定宽度类型,并提供检测转换不匹配的情况 (bpo-7767)。

  • PyUnicode_CompareWithASCIIString() 函数现在在 Python 字符串以 NUL 结尾时返回 不相等

  • 新增函数 PyErr_NewExceptionWithDoc(),类似于 PyErr_NewException(),但允许指定文档字符串。这使得 C 语言实现的异常能够像纯 Python 异常一样具备自文档化能力 (bpo-7033)。

  • 当使用 --with-valgrind 选项编译时,pymalloc 分配器在 Valgrind 下运行时会自动禁用。这提高了在 Valgrind 下运行时的内存泄漏检测能力,同时在其他时候利用 pymalloc (bpo-2422)。

  • PyArg_Parse 函数中移除了 O? 格式。该格式不再使用,且从未被文档化 (bpo-8837)。

There were a number of other small changes to the C-API. See the Misc/NEWS file for a complete list.

Also, there were a number of updates to the Mac OS X build, see Mac/BuildScript/README.txt for details. For users running a 32/64-bit build, there is a known problem with the default Tcl/Tk on Mac OS X 10.6. Accordingly, we recommend installing an updated alternative such as ActiveState Tcl/Tk 8.5.9. See https://www.python.org/download/mac/tcltk/ for additional details.

移植到 Python 3.2

本节列出了先前描述的改变以及可能需要修改你的代码的其他问题修正:

  • The configparser module has a number of clean-ups. The major change is to replace the old ConfigParser class with long-standing preferred alternative SafeConfigParser. In addition there are a number of smaller incompatibilities:

    • 插值语法现在在 get()set() 操作中进行验证。在默认的插值方案中,只有两个带有百分号的标记是有效的:%(name)s%%,后者是转义后的百分号。

    • set()add_section() 方法现在验证值是否为实际的字符串。以前,可能会无意引入不支持的类型。

    • 来自单个源的重复节或选项现在会引发 DuplicateSectionErrorDuplicateOptionError。此前,重复项会默默地覆盖先前的条目。

    • 内联注释现在默认禁用,因此现在可以安全地在值中使用 ; 字符。

    • 注释现在可以缩进。因此,为了在多行值的行首出现 ;#,必须进行插值。这样可以防止值中的注释前缀字符被误认为是注释。

    • "" 现在是一个有效值,不再自动转换为空字符串。对于空字符串,请在行中使用 "option ="

  • The nntplib module was reworked extensively, meaning that its APIs are often incompatible with the 3.1 APIs.

  • bytearray 对象不能再用作文件名;相反,它们应该转换为 bytes

  • The array.tostring() and array.fromstring() have been renamed to array.tobytes() and array.frombytes() for clarity. The old names have been deprecated. (See bpo-8990.)

  • PyArg_Parse*() 函数:

    • "t#" 格式已被移除:改用 "s#" 或 "s*"

    • "w" 和 "w#" 格式已被移除:改用 "w*"

  • The PyCObject type, deprecated in 3.1, has been removed. To wrap opaque C pointers in Python objects, the PyCapsule API should be used instead; the new type has a well-defined interface for passing typing safety information and a less complicated signature for calling a destructor.

  • The sys.setfilesystemencoding() function was removed because it had a flawed design.

  • random.seed() 函数和方法现在使用 sha512 哈希函数对字符串种子进行加盐。为了访问以前版本的 seed 以重现 Python 3.1 序列,将 version 参数设置为 1,即 random.seed(s, version=1)

  • The previously deprecated string.maketrans() function has been removed in favor of the static methods bytes.maketrans() and bytearray.maketrans(). This change solves the confusion around which types were supported by the string module. Now, str, bytes, and bytearray each have their own maketrans and translate methods with intermediate translation tables of the appropriate type.

    (由Georg Brandl在 bpo-5675 中贡献)

  • The previously deprecated contextlib.nested() function has been removed in favor of a plain with statement which can accept multiple context managers. The latter technique is faster (because it is built-in), and it does a better job finalizing multiple context managers when one of them raises an exception:

    with open('mylog.txt') as infile, open('a.out', 'w') as outfile:
        for line in infile:
            if '<critical>' in line:
                outfile.write(line)
    

    (由 Georg Brandl 和 Mattias Brändström 贡献; appspot issue 53094。)

  • struct.pack() 现在只允许使用字节类型(bytes)作为 s 字符串打包代码的参数。此前,该函数会接受文本类型(text)参数,并隐式地使用 UTF-8 编码将其转换为字节类型。这种做法存在两个问题:一是它对正确的编码方式做了预设假设;二是在将变长编码写入结构的固定长度字段时可能会导致失败。

    类似于 struct.pack('<6sHHBBB', 'GIF87a', x, y) 的代码应重写为使用字节串而不是文本,即 struct.pack('<6sHHBBB', b'GIF87a', x, y)

    (由 David Beazley 发现,并由 Victor Stinner 修复;参见 bpo-10783。)

  • xml.etree.ElementTree 类在解析失败时现在会抛出 xml.etree.ElementTree.ParseError。之前,它会抛出 xml.parsers.expat.ExpatError

  • 新的、更长的浮点数 str() 输出格式可能会导致依赖旧输出格式的 doctest 测试用例失效。

  • subprocess.Popen 中,close_fds 的默认值在 Unix 上现在为 True;在 Windows 上,如果三个标准流均设置为 None,则为 True,否则为 False。之前,close_fds 默认总是 False,这会导致打开的文件描述符泄露到子进程中,产生难以解决的错误或竞争条件。

  • 对旧式 HTTP 0.9 的支持已从 urllib.requesthttp.client 中移除。 此项支持仍然存在于服务器端(在 http.server 中)。

    (由 Antoine Pitrou 在 bpo-10711 中贡献。)

  • 超时模式下的 SSL 套接字现在如发生超时则会引发 socket.timeout,而不是一般性的 SSLError

    (由 Antoine Pitrou 在 bpo-10272 中贡献。)

  • The misleading functions PyEval_AcquireLock() and PyEval_ReleaseLock() have been officially deprecated. The thread-state aware APIs (such as PyEval_SaveThread() and PyEval_RestoreThread()) should be used instead.

  • Due to security risks, asyncore.handle_accept() has been deprecated, and a new function, asyncore.handle_accepted(), was added to replace it.

    (由 Giampaolo Rodola 在 bpo-6706 中贡献。)

  • 由于新的 GIL 实现,PyEval_InitThreads() 将不再能在 Py_Initialize() 之前被调用。