Python 3.2 的新特性

作者:

Raymond Hettinger

本文介绍了 Python 3.2 相较于 3.1 的新功能。Python 3.2 于 2011 年 2 月 20 日发布。它重点介绍了一些亮点并给出了一些示例。有关完整详细信息,请参阅 Misc/NEWS 文件。

另请参阅

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

Martin von Löwis 编写的 PEP。

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 - 新的命令行解析模块

Steven Bethard 编写的 PEP。

有关与 optparse 的差异的详细信息,请参阅将 optparse 代码迁移到 argparse

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

logging 模块提供了两种配置,一种样式是使用每个选项的函数调用,另一种样式是由以 configparser 格式保存的外部文件驱动。这些选项没有提供从 JSON 或 YAML 文件创建配置的灵活性,也没有支持增量配置,而增量配置对于从命令行指定记录器选项是必需的。

为了支持更灵活的样式,该模块现在提供了 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 - 用于日志记录的基于字典的配置

Vinay Sajip 编写的 PEP。

PEP 3148:concurrent.futures 模块

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

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

新模块的主要功能是一对用于启动和管理调用的执行器类。执行器的目标是使使用现有工具进行并行调用变得更加容易。它们节省了设置资源池、启动调用、创建结果队列、添加超时处理以及限制线程、进程或远程过程调用的总数所需的工作量。

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

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

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 – 异步执行计算

Brian Quinlan 编写的 PEP。

用于线程并行 URL 读取的代码,一个使用线程并行获取多个网页的示例。

用于并行计算素数的代码,一个演示 ProcessPoolExecutor 的示例。

PEP 3147:PYC 存储库目录

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

随着 Linux 发行版附带多个版本的 Python 变得司空见惯,“pyc 冲突”的问题变得更加突出。这些冲突也会在使用诸如 Unladen Swallow 等 CPython 替代方案时出现。

为了解决这个问题,Python 的导入机制已经扩展为针对每个解释器使用不同的文件名。现在,Python 3.2、Python 3.3 和 Unladen Swallow 不会再竞争名为“mymodule.pyc”的文件,而是会查找“mymodule.cpython-32.pyc”、“mymodule.cpython-33.pyc”和“mymodule.unladen10.pyc”。为了防止所有这些新文件使源目录变得杂乱,pyc 文件现在被收集在包目录下的“__pycache__”目录中。

除了文件名和目标目录之外,新方案还有一些对程序员可见的方面

  • 导入的模块现在有一个 __cached__ 属性,用于存储实际导入的文件的名称

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

    >>> import imp 
    >>> imp.get_tag() 
    'cpython-32'
    
  • 尝试从导入的文件推断源文件名的脚本现在需要更智能。仅仅从“.pyc”文件名中去掉“c”是不够的。相反,请使用 imp 模块中的新函数

    >>> 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__

  • importlib.abc 模块已使用用于加载字节码文件的新抽象基类进行了更新。过时的 ABC,PyLoaderPyPycLoader 已被弃用(有关如何保持与 Python 3.1 兼容的说明包含在文档中)。

另请参阅

PEP 3147 - PYC 存储库目录

由 Barry Warsaw 编写的 PEP。

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 文件

由 Barry Warsaw 编写的 PEP。

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

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

该 PEP 区分了所谓的本地字符串(用于请求/响应标头和元数据)和字节字符串(用于请求和响应的主体)。

本地字符串始终是 str 类型,但仅限于 U+0000U+00FF 之间的代码点,这些代码点可以使用 Latin-1 编码转换为字节。这些字符串用于环境字典中的键和值,以及 start_response() 函数中的响应标头和状态。它们必须遵循 RFC 2616 关于编码的规定。也就是说,它们必须是 ISO-8859-1 字符或使用 RFC 2047 MIME 编码。

对于从 Python 2 移植 WSGI 应用程序的开发人员,以下是重点

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

  • 如果应用程序改为编码输出标头或解码输入标头,则标头将需要重新编码为 Latin-1。例如,使用 h.encode('utf-8') 编码为 utf-8 的输出标头现在需要使用 h.encode('utf-8').decode('latin-1') 从字节转换为本地字符串。

  • 应用程序产生的值或使用 write() 方法发送的值必须是字节字符串。start_response() 函数和 environ 必须使用本地字符串。两者不能混用。

对于编写 CGI 到 WSGI 通道或其他 CGI 风格协议的服务器实现者,用户必须能够使用本地字符串访问环境,即使底层平台可能有不同的约定。为了弥合这一差距,wsgiref 模块有一个新函数,wsgiref.handlers.read_environ() 用于将 CGI 变量从 os.environ 转码为本地字符串并返回一个新字典。

另请参阅

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

由 Phillip Eby 编写的 PEP。

其他语言更改

对核心 Python 语言进行的一些较小的更改是

  • 用于 format()str.format() 的字符串格式化获得了格式字符 # 的新功能。以前,对于二进制、八进制或十六进制的整数,它会导致输出分别以“0b”、“0o”或“0x”作为前缀。现在它也可以处理浮点数、复数和 Decimal,导致输出始终有一个小数点,即使后面没有数字。

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

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

  • 还有一个新的 str.format_map() 方法,它通过接受任意的 映射 对象来扩展现有 str.format() 方法的功能。这种新方法使得可以使用字符串格式化来处理任何 Python 的类字典对象,例如 defaultdictShelfConfigParserdbm。它也适用于自定义的 dict 子类,这些子类在查找之前对键进行规范化,或者为未知键提供 __missing__() 方法

    >>> 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 中实现。)

  • 解释器现在可以使用 quiet 选项 -q 启动,以防止在交互模式下显示版权和版本信息。该选项可以使用 sys.flags 属性进行自省

    $ 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 中贡献。)

  • hasattr() 函数的工作原理是调用 getattr() 并检测是否引发了异常。此技术允许它检测由 __getattr__()__getattribute__() 动态创建的方法,否则这些方法将不会出现在类字典中。以前,hasattr 会捕获任何异常,可能会掩盖真正的错误。现在,hasattr 已收紧为仅捕获 AttributeError,并让其他异常通过

    >>> 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 对象现在拥有 release() 方法,并且还支持上下文管理协议。 这允许及时释放从原始对象请求缓冲区时获得的任何资源。

    >>> 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。)

  • 结构序列类型 现在是元组的子类。这意味着像 os.stat()time.gmtime()sys.version_info 返回的 C 结构现在像一个 具名元组 一样工作,并且现在可以与期望元组作为参数的函数和方法一起使用。这在使 C 结构的灵活性与纯 Python 版本相当方面迈出了重要一步。

    >>> 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 模块提供的方法或在命令行中启用此警告。

    如果 gc.garbage 列表不为空,并且如果设置了 gc.DEBUG_UNCOLLECTABLE,则会在解释器关闭时发出 ResourceWarning,并打印所有无法收集的对象。 这旨在提醒程序员他们的代码包含对象最终化问题。

    文件对象 在没有被显式关闭的情况下被销毁时,也会发出 ResourceWarning。虽然此类对象的 deallocator 确保它关闭底层操作系统资源(通常是文件描述符),但延迟 deallocating 对象可能会产生各种问题,尤其是在 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 对象现在支持 indexcount 方法。 这是为了使更多对象完全实现 collections.Sequence 抽象基类 的一部分工作。因此,该语言将具有更统一的 API。此外,range 对象现在支持切片和负索引,即使值大于 sys.maxsize。这使得 range 与列表更具互操作性。

    >>> 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 中贡献。)

  • 来自 Py2.x 的 callable() 内置函数被重新启用。它提供了一个简洁易读的替代方案,可以在像 isinstance(x, collections.Callable) 这样的表达式中使用 抽象基类

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

    (参见 bpo-10518。)

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

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

新增、改进和已弃用的模块

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

Python 3.2 的最大新闻是 email 包、mailbox 模块和 nntplib 模块现在可以在 Python 3 中正确使用字节/文本模型。这是第一次正确处理具有混合编码的消息。

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

另一个重大的成功是增加了对 SSL 连接和安全证书的实质性更好支持。

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

电子邮件

在 R. David Murray 的大量努力下,Python 3 中 email 包的可用性已基本修复。问题是电子邮件通常以 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 的消息正文。

  • 现在,smtplib 模块的 SMTP 类接受字节字符串作为 sendmail() 方法的 *msg* 参数,并且新增了一个 send_message() 方法,该方法接受一个 Message 对象,并且可以选择直接从该对象获取 *from_addr* 和 *to_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)
    

    如果更新了电话号码表,则可以使用以下方法清除缓存的过时内容

    >>> get_phone_number.cache_clear()
    

    (由 Raymond Hettinger 贡献,并结合了 Jim Baker、Miki Tebeka 和 Nick Coghlan 的设计理念;请参阅 recipe 498245recipe 577479bpo-10586bpo-10593。)

  • 现在,functools.wraps() 装饰器添加了一个指向原始可调用函数的 __wrapped__ 属性。这允许对包装的函数进行内省。如果定义了 __annotations__,它也会复制该属性。现在,它还会优雅地跳过丢失的属性,例如 __doc__,该属性可能未为包装的可调用对象定义。

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

    >>> get_phone_number = get_phone_number.__wrapped__    # uncached function
    

    (由 Nick Coghlan 和 Terrence Cole 编写;bpo-9567bpo-3445bpo-8814。)

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

    例如,提供 *__eq__* 和 *__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() 函数将旧式比较函数转换为现代的 键函数

    >>> # 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() 的示例,请参阅 随机模块的示例

    (由 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)

在此示例中,屏障强制执行更健壮的规则。如果某些投票站未在午夜之前完成,则屏障会超时,选票将被密封并放入队列中以便稍后处理。

有关如何在并行计算中使用屏障的更多示例,请参阅 屏障同步模式。此外,在 《信号量小书》 的 *第 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 年。

  • 每当在时间元组中使用两位数年份时,其解释都由 time.accept2dyear 控制。默认值为 True,这意味着对于两位数年份,世纪将根据控制 %y strptime 格式的 POSIX 规则进行猜测。

    从 Py3.2 开始,使用世纪猜测启发式方法会发出 DeprecationWarning。相反,建议将 time.accept2dyear 设置为 False,以便可以在没有猜测的情况下使用较大的日期范围

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

    现在有几个函数的日期范围已显著扩大。当 time.accept2dyear 为 false 时,time.asctime() 函数将接受适合 C int 的任何年份,而 time.mktime()time.strftime() 函数将接受相应操作系统函数支持的完整范围。

(由 Alexander Belopolsky 和 Victor Stinner 在 bpo-1289118bpo-5094bpo-6641bpo-2706bpo-1777412bpo-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() 函数计算小 x 值的 e**x-1,而不会出现通常伴随几乎相等量的减法而导致的精度损失

>>> 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

在为自定义容器编写 __repr__() 方法时,很容易忘记处理成员引用回容器本身的情况。Python 的内置对象(例如 listset)通过在表示字符串的递归部分显示“...”来处理自引用。

为了帮助编写这样的 __repr__() 方法,reprlib 模块有一个新的装饰器 recursive_repr(),用于检测对 __repr__() 的递归调用并替换为一个占位符字符串。

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

如果在发生日志记录事件之前没有设置任何配置,则现在会有一个默认配置,该配置使用一个 StreamHandler,针对 WARNING 级别或更高级别的事件定向到 sys.stderr。以前,在设置配置之前发生的事件要么引发异常,要么根据 logging.raiseExceptions 的值静默地删除事件。新的默认处理程序存储在 logging.lastResort 中。

过滤器的使用已得到简化。谓词可以是任何返回 TrueFalse 的 Python 可调用对象,而不是创建 Filter 对象。

还有许多其他改进增加了灵活性并简化了配置。有关 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))

一些哈希细节通过一个新的属性 sys.hash_info 公开,该属性描述了哈希值的位宽、质数模数、无穷大nan 的哈希值,以及用于数字虚部的乘数。

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

早期限制各种数字类型互操作性的决定已经放宽。仍然不支持(并且不明智)在算术表达式(例如 Decimal('1.1') + float('1.1'))中进行隐式混合,因为后者在构造二进制浮点数过程中会丢失信息。但是,由于现有的浮点值可以无损地转换为十进制或有理数表示,因此将它们添加到构造函数并支持混合类型比较是有意义的。

fractions.Fraction 进行了类似的更改,使得不再需要 from_float()from_decimal() 方法(bpo-8294

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

对于 decimal 模块的另一个有用的更改是,Context.clamp 属性现在是公共的。这对于创建与 IEEE 754 中指定的十进制交换格式相对应的上下文非常有用(请参阅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

select 模块现在公开一个新的常量属性 PIPE_BUF,它给出了当 select.select() 表示管道已准备好写入时,保证不会阻塞的最小字节数。

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

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

gzip 和 zipfile

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

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 中贡献。)

此外,zipfile.ZipExtFile 类在内部进行了重新设计,以表示存储在存档中的文件。新的实现速度明显更快,并且可以包装在 io.BufferedReader 对象中以获得更高的速度。它还解决了交错调用 *read* 和 *readline* 给出错误结果的问题。

(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'

某些操作系统允许直接访问环境变量中的编码字节。如果允许,os.supports_bytes_environ 常量将为真。

要直接访问编码的环境变量(如果可用),请使用新的 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 文件和 bzip2 压缩的 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 对象现在有一个 detach() 方法,该方法将套接字置于关闭状态,而实际上不关闭底层文件描述符。然后,后者可以重新用于其他目的。(由 Antoine Pitrou 添加;bpo-8524。)

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

ssl

ssl 模块添加了许多功能,以满足安全(加密、身份验证)互联网连接的常见要求

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

  • 一个新函数 ssl.match_hostname(),通过实现 HTTPS 的规则(来自 RFC 2818),支持更高级别协议的服务器身份验证,这些规则也适用于其他协议。

  • ssl.wrap_socket() 构造函数现在采用 ciphers 参数。ciphers 字符串使用 OpenSSL 文档中描述的格式列出允许的加密算法。

  • 当与最新版本的 OpenSSL 链接时,ssl 模块现在支持 TLS 协议的服务器名称指示扩展,允许在单个 IP 端口上使用不同证书的多个“虚拟主机”。此扩展仅在客户端模式下受支持,并通过将 server_hostname 参数传递给 ssl.SSLContext.wrap_socket() 激活。

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

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

  • 现在可以使用模块属性 ssl.OPENSSL_VERSION(字符串)、ssl.OPENSSL_VERSION_INFO(5 元组)和 ssl.OPENSSL_VERSION_NUMBER(整数)访问正在使用的 OpenSSL 版本。

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

nntp

nntplib 模块有一个改进的实现,具有更好的字节和文本语义以及更实用的 API。这些改进破坏了与 Python 3.1 中 nntplib 版本的兼容性,而该版本本身在某种程度上存在功能障碍。

还添加了对通过隐式(使用 nntplib.NNTP_SSL)和显式(使用 nntplib.NNTP.starttls())TLS 进行安全连接的支持。

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

证书

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 连接的源地址(主机,端口)元组。

对证书检查和 HTTPS 虚拟主机的支持已添加到 HTTPSConnection

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

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

为了与 http.server 的行为相匹配,HTTP 客户端库现在也使用 ISO-8859-1 (Latin-1) 编码对标头进行编码。它已经对传入的标头执行此操作,因此现在传入和传出的流量行为是一致的。(请参阅 Armin Ronacher 在 bpo-10980 中的工作。)

unittest

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

  • 命令行调用 python -m unittest 现在可以接受文件路径而不是模块名称来运行特定的测试(bpo-10620)。新的测试发现可以在包中查找测试,定位可从顶级目录导入的任何测试。可以使用 -t 选项指定顶级目录,使用 -p 指定匹配文件的模式,并使用 -s 指定开始发现的目录。

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

    (由 Michael Foord 贡献。)

  • 在交互式提示符下进行实验现在更容易,因为 unittest.TestCase 类现在可以在没有参数的情况下实例化

    >>> 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 属性,用于设置显示差异的最大长度。

  • 此外,模块中的方法名称也进行了一些清理。

    例如,assertRegex()assertRegexpMatches() 的新名称,后者的命名不正确,因为测试使用 re.search(),而不是 re.match()。其他使用正则表达式的方法现在使用简称“Regex”而不是“Regexp”命名——这与在其他 unittest 实现中使用的名称匹配,与 Python 的 re 模块的旧名称匹配,并且具有明确的驼峰式大小写。

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

  • 为了提高一致性,一些长期存在的方法别名将被弃用,以支持首选名称

    旧名称

    首选名称

    assert_()

    assertTrue()

    assertEquals()

    assertEqual()

    assertNotEquals()

    assertNotEqual()

    assertAlmostEquals()

    assertAlmostEqual()

    assertNotAlmostEquals()

    assertNotAlmostEqual()

    同样,在 Python 3.1 中弃用的 TestCase.fail* 方法预计将在 Python 3.3 中删除。

    (由 Ezio Melotti 贡献;bpo-9424。)

  • assertDictContainsSubset() 方法已被弃用,因为它的实现顺序错误。这产生了难以调试的视觉错觉,例如 TestCase().assertDictContainsSubset({'a':1, 'b':2}, {'a':1}) 等测试会失败。

    (由 Raymond Hettinger 贡献。)

random

random 模块中的整数方法现在可以更好地生成均匀分布。以前,它们使用 int(n*random()) 计算选择,当 *n* 不是 2 的幂时,它会产生轻微的偏差。现在,从直到下一个 2 的幂的范围内进行多次选择,并且仅当选择落在 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 现在提供了一个 handle_accepted() 方法,返回一个 (sock, addr) 对,当与新的远程端点实际建立连接时调用。这应该用作旧的 handle_accept() 的替代品,并避免用户直接调用 accept()

(由 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

pydoc 模块现在提供了一个经过大幅改进的 Web 服务器界面,以及一个新的命令行选项 -b,用于自动打开浏览器窗口来显示该服务器。

$ 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 模块可以轻松发现跨平台和安装而变化的安装路径和配置变量。

该模块提供对平台和版本信息的简单访问函数

它还提供对与 distutils 使用的七个命名方案之一对应的路径和变量的访问。这些包括 *posix_prefix*、*posix_home*、*posix_user*、*nt*、*nt_user*、*os2*、*os2_home*。

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

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"

(由 Tarek Ziadé 从 Distutils 中移出。)

pdb

pdb 调试器模块获得了一些可用性方面的改进。

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

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

  • Pdb 类构造函数现在接受 *nosigint* 参数。

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

  • 新命令:displayundisplay 用于显示或隐藏表达式的值(如果已更改)。

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

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

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

configparser

configparser 模块被修改以提高默认解析器及其支持的 INI 语法的可用性和可预测性。旧的 ConfigParser 类被删除,取而代之的是 SafeConfigParser,后者又被重命名为 ConfigParser。默认情况下,现在已关闭对内联注释的支持,并且在单个配置源中不允许出现节或选项重复。

配置解析器获得了一个基于映射协议的新 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 函数指定回退值或直接从字典和字符串读取。

(所有更改均由 Ł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('https://pythonlang.cn/about/#target')
>>> r
DefragResult(url='https://pythonlang.cn/about/', fragment='target')
>>> r[0]
'https://pythonlang.cn/about/'
>>> r.fragment
'target'

并且,urlencode() 函数现在更加灵活,接受字符串或字节类型的 *query* 参数。如果它是字符串,则将 *safe*、*encoding* 和 *error* 参数发送到 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'https://pythonlang.cn: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 更改。

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

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

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

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

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

turtledemo

turtle 模块的演示代码已从 *Demo* 目录移动到主库。它包括十几个带有生动显示的示例脚本。因为它在 sys.path 中,现在可以直接从命令行运行

$ python -m turtledemo

(由 Alexander Belopolsky 从 Demo 目录移动,在 bpo-10199 中。)

多线程

  • 用于序列化并发运行的 Python 线程执行的机制(通常称为 GIL 或全局解释器锁)已被重写。目标包括更可预测的切换间隔,并减少由于锁竞争和随后的系统调用次数而产生的开销。允许线程切换的“检查间隔”的概念已被放弃,取而代之的是以秒为单位表示的绝对持续时间。此参数可以通过 sys.setswitchinterval() 进行调整。目前,它的默认值为 5 毫秒。

    有关实现的更多详细信息,可以从 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 的窥孔优化器现在识别诸如 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 中贡献。)

  • 当使用 key 函数 调用时,Timsort 算法(在 list.sort()sorted() 中使用)现在运行速度更快,使用的内存更少。以前,列表中的每个元素都被包装在一个临时对象中,该对象记住与每个元素关联的键值。现在,两个键和值的数组并行排序。这样可以节省排序包装器消耗的内存,并节省因委托比较而浪费的时间。

    (由 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。)

  • stringlib 中的快速搜索算法现在被 split()rsplit()splitlines()replace() 方法用于 bytesbytearraystr 对象。同样,该算法也用于 rfind()rindex()rsplit()rpartition()

    (由 Florent Xicluna 在 bpo-7622bpo-7462 中贡献的补丁。)

  • 现在,整数到字符串的转换一次处理两位数,从而减少了除法和模运算的次数。

    bpo-6713 由 Gawain Bolton、Mark Dickinson 和 Victor Stinner 贡献。)

还有一些其他的细微优化。现在,当一个操作数比另一个操作数大得多时,集合差分运算的运行速度更快(Andress Bennetts 的补丁,见 bpo-8685)。array.repeat() 方法有了更快的实现(Alexander Belopolsky 的贡献,见 bpo-1569291)。BaseHTTPRequestHandler 具有更高效的缓冲机制(Andrew Schaaf 的贡献,见 bpo-3709)。operator.attrgetter() 函数的速度得到了提升(Christos Georgiou 的贡献,见 bpo-10160)。ConfigParser 加载多行参数的速度略有提升(Łukasz Langa 的贡献,见 bpo-7113)。

Unicode

Python 已更新至 Unicode 6.0.0。此标准更新增加了 2000 多个新字符,包括对移动电话很重要的 表情符号

此外,更新的标准修改了两个卡纳达字符 (U+0CF1, U+0CF2) 和一个新傣仂数字字符 (U+19DA) 的字符属性,使得前者有资格用于标识符,而后者则被取消资格。更多信息,请参阅 Unicode 字符数据库更改

编解码器

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

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

MBCS 编解码器支持解码的 'strict''ignore' 错误处理程序,以及编码的 'strict''replace' 错误处理程序。

要模拟 Python3.1 的 MBCS 编码,请为解码选择 'ignore' 处理程序,为编码选择 'replace' 处理程序。

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

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

文档

文档持续改进中。

  • 在较长的章节顶部添加了快速链接表,例如 内置函数。在 itertools 的情况下,链接附有速查表式的摘要表,以便在不必阅读所有文档的情况下提供概述和记忆提示。

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

    源代码 Lib/functools.py

    (由 Raymond Hettinger 贡献;请参阅 理由。)

  • 文档现在包含更多示例和配方。特别是,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。)

代码存储库

除了现有的 Subversion 代码存储库 https://svn.python.org 之外,现在还有一个 Mercurial 存储库,网址为 https://hg.python.org/

在 3.2 版本发布后,计划切换到 Mercurial 作为主要存储库。这种分布式版本控制系统应该使社区成员更容易创建和共享外部变更集。有关详细信息,请参阅 PEP 385

要了解如何使用新的版本控制系统,请参阅 快速入门Mercurial 工作流程指南

构建和 C API 更改

Python 的构建过程和 C API 的更改包括

  • idlepydoc2to3 脚本现在在 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。)

  • 现在,在受支持的编译器上默认启用计算的 goto(由配置脚本检测)。仍然可以通过指定 --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。)

  • 新的宏 Py_VA_COPY 复制可变参数列表的状态。它等效于 C99 的 va_copy,但在所有 Python 平台上都可用 (bpo-2443)。

  • 新的 C API 函数 PySys_SetArgvEx() 允许嵌入式解释器设置 sys.argv,而无需同时修改 sys.path (bpo-5753)。

  • 现在,PyEval_CallObject() 仅以宏的形式提供。为了向后兼容而保留的函数声明已被移除——该宏是在 1997 年引入的 (bpo-8276)。

  • 新增了一个函数 PyLong_AsLongLongAndOverflow(),它类似于 PyLong_AsLongAndOverflow()。它们都用于将 Python int 转换为本机固定宽度类型,同时检测转换不适合的情况 (bpo-7767)。

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

  • 新增了一个函数 PyErr_NewExceptionWithDoc(),它类似于 PyErr_NewException(),但允许指定文档字符串。这使得 C 异常具有与其纯 Python 对应项相同的自文档化能力 (bpo-7033)。

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

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

C-API 还有一些其他的细微更改。有关完整列表,请参阅 Misc/NEWS 文件。

此外,Mac OS X 构建也有一些更新,详细信息请参阅 Mac/BuildScript/README.txt。对于运行 32/64 位构建的用户,Mac OS X 10.6 上的默认 Tcl/Tk 存在已知问题。因此,我们建议安装更新的替代方案,例如 ActiveState Tcl/Tk 8.5.9。有关更多详细信息,请参阅 https://pythonlang.cn/download/mac/tcltk/

移植到 Python 3.2

本节列出了之前描述的更改和其他错误修复,这些更改和修复可能需要修改您的代码

  • configparser 模块进行了一些清理。主要的更改是用长期以来首选的替代方案 SafeConfigParser 替换旧的 ConfigParser 类。此外,还有一些较小的兼容性问题

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

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

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

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

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

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

  • nntplib 模块进行了大量修改,这意味着其 API 通常与 3.1 API 不兼容。

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

  • array.tostring()array.fromstring() 已重命名为 array.tobytes()array.frombytes(),以使其更清晰。旧名称已弃用。(请参阅 bpo-8990。)

  • PyArg_Parse*() 函数

    • “t#” 格式已被删除:请改用 “s#” 或 “s*”

    • “w” 和 “w#” 格式已被删除:请改用 “w*”

  • 已删除 3.1 中已弃用的 PyCObject 类型。要在 Python 对象中包装不透明的 C 指针,应改用 PyCapsule API;新类型具有用于传递类型安全信息的良好定义的接口,以及用于调用析构函数的更简单的签名。

  • 由于其设计存在缺陷,sys.setfilesystemencoding() 函数已被删除。

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

  • 先前已弃用的 string.maketrans() 函数已被删除,取而代之的是静态方法 bytes.maketrans()bytearray.maketrans()。此更改解决了 string 模块支持哪些类型的困惑。现在,strbytesbytearray 各自都有自己的 maketranstranslate 方法,其中包含相应类型的中间转换表。

    (由 Georg Brandl 贡献;bpo-5675。)

  • 先前已弃用的 contextlib.nested() 函数已被删除,取而代之的是普通的 with 语句,该语句可以接受多个上下文管理器。后一种技术更快(因为它是内置的),并且当其中一个上下文管理器引发异常时,它可以更好地完成多个上下文管理器的最终处理

    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() 现在只允许使用字节作为 s 字符串打包代码。以前,它会接受文本参数并使用 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 中,Unix 下 close_fds 的默认值现在为 True;在 Windows 下,如果三个标准流都设置为 None,则为 True,否则为 False。 之前,close_fds 默认值始终为 False,这会在打开的文件描述符泄漏到子进程中时产生难以解决的错误或竞争条件。

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

    (由 Antoine Pitrou 贡献,bpo-10711。)

  • 现在,当超时发生时,超时模式下的 SSL 套接字会引发 socket.timeout 异常,而不是通用的 SSLError 异常。

    (由 Antoine Pitrou 贡献,bpo-10272。)

  • 具有误导性的函数 PyEval_AcquireLock()PyEval_ReleaseLock() 已被正式弃用。 应该使用线程状态感知 API(例如 PyEval_SaveThread()PyEval_RestoreThread())。

  • 由于安全风险,asyncore.handle_accept() 已被弃用,并添加了一个新函数 asyncore.handle_accepted() 来替代它。

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

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