Python 3.2 有什么新变化
***********************

作者:
   Raymond Hettinger（译者：wh2099 at outlook dot com）

这篇文章介绍了 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
     PEP 由 Martin von Löwis 撰写。


PEP 389: Argparse 命令行解析模块
================================

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

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

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

   import argparse
   parser = argparse.ArgumentParser(
               description = '管理服务器',         # 帮助中的主要描述
               epilog = '已在Solaris和Linux上测试') # 要求帮助后显示的内容
   parser.add_argument('action',                       # 参数名称
               choices = ['deploy', 'start', 'stop'],  # 三个允许的值
               help = '对每个目标执行的操作')         # 帮助信息
   parser.add_argument('targets',
               metavar = 'HOSTNAME',                   # 帮助信息中使用的变量名
               nargs = '+',                            # 需要一个或多个目标
               help = '目标机器的URL')               # 帮助信息解释
   parser.add_argument('-u', '--user',                 # -u 或 --user 选项
               required = True,                        # 使其成为必需参数
               help = '以用户身份登录')

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

   >>> 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')   # 第一个子分组
   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',        # 第二个子分组
                                    aliases=('steer', 'turn'))         # 等价的名称
   parser_m.add_argument('-c', '--course', type=int, required=True)
   parser_m.add_argument('-s', '--speed', type=int, default=0)

   $ ./helm.py --help                         # 最高层级的帮助 (launch 和 move)
   $ ./helm.py launch --help                  # launch 选项的帮助
   $ ./helm.py launch --missiles              # 设置 missiles=True 及 torpedos=False
   $ ./helm.py steer --course 180 --speed 5   # 设置动作形参

参见:

  **PEP 389** - 新的命令行解析模块
     PEP 由 Steven Bethard 撰写。

  参阅 将 optparse 代码迁移至 argparse 了解与 "optparse" 的差异的细节
  。


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** - 基于字典的日志配置
     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__" 的目录中，该目录存放在包目录下。

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

* 导入的模块现在具有一个 "__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_compile" 和 "compileall" 模块已更新以反映新的命名约定和目标目录
  。*compileall* 的命令行调用有了新选项："-i" 用于指定要编译的文件和目
  录列表，"-b" 使字节码文件写入其传统位置而非 *__pycache__*。

* "importlib.abc" 模块已更新，包含用于加载字节码文件的新 *抽象基类*。
  已弃用的ABCs，"PyLoader" 和 "PyPycLoader" (如何保持与 Python 3.1 兼
  容的说明包含在文档中) 。

参见:

  **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')       # 查找版本标签
   'cpython-32mu'
   >>> sysconfig.get_config_var('EXT_SUFFIX')  # 查找完整文件名扩展
   '.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)。

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

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

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

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

* 应用程序生成的值或使用 "write()" 方法发送的值必须是字节字符串。
  "start_response()" 函数和环境必须使用原生字符串。两者不能混用。

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

参见:

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

* 还有一个新的 "str.format_map()" 方法，它通过接受任意的 *mapping* 对
  象，扩展了现有 "str.format()" 方法的功能。这个新方法使得可以使用字符
  串格式化与Python的许多字典类对象，如 "defaultdict"、"Shelf"、
  "ConfigParser" 或 "dbm"。它也适用于在查找前标准化键的自定义 "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 中实现。）

* 解释器现在可以带有一个安静选项 "-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()
             # 在此隐式执行 "del e"

  （参见 bpo-4617。）

* 结构体序列类型 现在是 tuple 的子类。这意味着像 "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"。尽管此类对象的析构函数确保关闭底层的操作系统资源
  （通常是文件描述符），但对象释放的延迟可能导致各种问题，特别是在
  Windows 系统下。以下是通过命令行启用该警告的示例：

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

  （由 Antoine Pitrou 和 Georg Brandl 在 bpo-10093 和 bpo-477863 中添
  加。）

* "range" 对象现在支持 *index* 和 *count* 方法。这是为了让更多对象完全
  实现 "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 中贡献。）

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

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

  （参见 bpo-10518。）

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

   （需要 Victor Stinner 在 bpo-9425 中做大量工作。）


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

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

Python 3.2 最重要的更新是："email" 包、"mailbox" 模块以及 "nntplib" 模
块现在能够正确支持 Python 3 的字节/文本模型。这是首次实现对混合编码邮
件的正确处理。

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

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

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


email
-----

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

* 新函数 "message_from_bytes()" 和 "message_from_binary_file()"，以及
  新类 "BytesFeedParser" 和 "BytesParser" 允许将二进制消息数据解析为模
  型对象。

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

* 给定模型的字节输入，"Generator" 将把具有 *Content-Transfer-Encoding*
  为 *8bit* 的消息正文转换为具有 *7bit* 的 *Content-Transfer-Encoding*
  。

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

* 一个新的类 "BytesGenerator" 生成字节输出，保留输入中未更改的任何非
  ASCII 数据，包括具有 *Content-Transfer-Encoding* 为 *8bit* 的消息正
  文。

* "smtplib" 的 "SMTP" 类现在接受字节字符串作为 "sendmail()" 方法的
  *msg* 参数，并且一个新的方法 "send_message()" 接受一个 "Message" 对
  象，并可以可选地从对象中直接获取 *from_addr* 和 *to_addrs* 地址。

（由 R. David Murray 在 bpo-4661 和 bpo-10321 中提议并实现。）


elementtree
-----------

"xml.etree.ElementTree" 包及其 "xml.etree.cElementTree" 对应版本已更新
到 1.3。

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

* "xml.etree.ElementTree.fromstringlist()" 可根据一系列片段生成 XML 文
  档

* "xml.etree.ElementTree.register_namespace()" 用于注册全局命名空间前
  缀

* "xml.etree.ElementTree.tostringlist()" 用于字符串表示包括所有子列表

* "xml.etree.ElementTree.Element.extend()" 用于添加包含零个或多个元素
  的序列

* "xml.etree.ElementTree.Element.iterfind()" 可搜索元素和子元素

* "xml.etree.ElementTree.Element.itertext()" 创建一个包含指定元素及其
  子元素的文本迭代器。

* "xml.etree.ElementTree.TreeBuilder.end()" 关闭当前元素

* "xml.etree.ElementTree.TreeBuilder.doctype()" 处理 doctype 声明

两个方法被弃用：

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

  （由 Raymond Hettinger 贡献，并融合了 Jim Baker、Miki Tebeka 和 Nick
  Coghlan 的设计理念；参见 recipe 498245、recipe 577479、bpo-10586 和
  bpo-10593。）

* "functools.wraps()" 装饰器现在添加了一个指向原始可调用函数的
  "__wrapped__" 属性。这使得包装函数可以被内省。它还会复制定义的
  "__annotations__"。现在它也能优雅地跳过缺失的属性，如可能未为包装的
  可调用对象定义的 "__doc__"。

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

  >>> get_phone_number = get_phone_number.__wrapped__    # uncached function

  （由 Nick Coghlan 和 Terrence Cole 在 bpo-9567, bpo-3445 和 bpo-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()" 函数可将旧式的比
  较函数转换为新式的 *键函数*:

  >>> # 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()        # 在所有投票站关闭之前不要计数
       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" 相乘，并且可以被 "float" 和
  "int" 对象除。同时，"timedelta" 对象现在可以相互除。

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

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

  从 Py3.2 开始，使用世纪猜测启发式方法将发出 "DeprecationWarning" 警
  告。建议将 "time.accept2dyear" 设置为 "False"，以便在没有猜测的情况
  下使用大的日期范围:

     >>> import time, warnings
     >>> warnings.resetwarnings()      # 移除默认的警告过滤器

     >>> time.accept2dyear = True      # 猜测 11 是指 11 还是 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     # 使用允许的完整日期范围
     >>> time.asctime((11, 1, 1, 12, 34, 56, 4, 1, 0))
     'Fri Jan  1 12:34:56 11'

  多个函数的日期范围已显著扩展。当 "time.accept2dyear" 为假时，
  "time.asctime()" 函数将接受任何适合 C int 类型的年份，而
  "time.mktime()" 和 "time.strftime()" 函数将接受相应操作系统函数支持
  的全部范围。

（由 Alexander Belopolsky 和 Victor Stinner 在 bpo-1289118、 bpo-5094
、 bpo-6641、 bpo-2706、 bpo-1777412、 bpo-8013 和 bpo-10827 中贡献。
）


math
----

"math" 模块已更新，新增了六个借鉴自 C99 标准的函数。

"isfinite()" 函数提供了一种可靠且快速的方法来检测特殊值。它对常规数字
返回 "True"，对 *Nan* 或 *Infinity* 返回 "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))   # 在 1 个标准差内的正态分布部分
   0.682689492137086
   >>> erfc(1.0/sqrt(2.0))  # 在 1 个标准差外的正态分布部分
   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的内置对象如 "list" 和 "set" 通过在表示字符串的递归部分
显示 "..." 来处理自引用。

为了帮助编写此类 "__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-9826 和 bpo-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" 中。

过滤器的使用已经简化。现在不再需要创建 "Filter" 对象，谓词可以是任何返
回 "True" 或 "False" 的 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))

一些哈希细节通过新的属性 "sys.hash_info" 公开，该属性描述了哈希值的位
宽、素数模数、*infinity* 和 *nan* 的哈希值，以及用于数字虚部的乘数：

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

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

* "decimal.Decimal" 构造函数现在直接接受 "float" 对象，因此不再需要使
  用 "from_float()" 方法（bpo-8257）。

* 现在完全支持混合类型比较，以便 "Decimal" 对象可以直接与 "float" 和
  "fractions.Fraction" 进行比较（bpo-2531 和 bpo-8188）。

对 "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.mmap" 和 "fileinput.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-8046 和 bpo-1286 贡献。）

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

（由 Giampaolo Rodolà 在 bpo-8806 中贡献。）


popen
-----

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

（由 Antoine Pitrou 和 Brian Curtin 在 bpo-7461 和 bpo-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()" 方法，并支持不可 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-9962、 bpo-1675951 、 bpo-7471 和 bpo-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():             # 仅保存真实文件
   ...         tarinfo.uname = 'monty'      # 涂改用户名
   ...         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 将 "bytes" 和 "set" 字面量添加到支持的类型
列表中：字符串、字节、数字、元组、列表、字典、集合、布尔值和 "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 文件和 bzip 压缩的 tar 文件的 归档操作。还有用于注册其他归档文件格
式（如 xz 压缩的 tar 文件或自定义格式）的函数。

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

   >>> import shutil, pprint

   >>> os.chdir('mydata')  # 切换到源目录
   >>> f = shutil.make_archive('/var/backup/mydata',
   ...                         'zip')      # 将当前目录归档
   >>> f                                   # 显示归档文件名
   '/var/backup/mydata.zip'
   >>> os.chdir('tmp')                     # 切换到解包目录
   >>> shutil.unpack_archive('/var/backup/mydata.zip')  # 恢复数据

   >>> pprint.pprint(shutil.get_archive_formats())  # 显示已知格式
   [('bztar', "bzip2'ed tar-file"),
    ('gztar', "gzip'ed tar-file"),
    ('tar', 'uncompressed tar file'),
    ('zip', 'ZIP file')]

   >>> shutil.register_archive_format(     # 注册新的归档格式
   ...     name='xz',
   ...     function=xz.compress,           # 可调用的归档函数
   ...     extra_args=[('level', 8)],      # 传给该函数的参数
   ...     description='xz compression'
   ... )

（由 Tarek Ziadé 贡献。）


sqlite3
-------

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

* "sqlite3.Connection.in_transit" 属性为真，表示存在未提交更改的活跃事
  务。

* "sqlite3.Connection.enable_load_extension()" 和
  "sqlite3.Connection.load_extension()" 方法允许你从 ".so" 文件加载
  SQLite 扩展。一个著名的扩展是随 SQLite 分发的全文搜索扩展。

（由 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 协议的服务器
  名称指示（Server Name Indication，SNI）扩展。该特性允许在单个 IP 端
  口上为多个使用不同证书的“虚拟主机”提供服务。需要注意的是，此扩展仅在
  客户端模式下受支持，并且需要通过向 "ssl.SSLContext.wrap_socket()" 方
  法传递 *server_hostname* 参数来激活。

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

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

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

（由 Antoine Pitrou 在 bpo-8850、 bpo-1589、 bpo-8322、 bpo-5639、
bpo-4870、 bpo-8484 和 bpo-8321 中贡献。）


nntp
----

"nntplib" 模块进行了重新实现，改进了字节和文本语义以及更实用的API。这
些改进破坏了与Python 3.1中nntplib版本的兼容性，后者本身部分功能不完善
。

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

（由 Antoine Pitrou 在 bpo-9360 中贡献，由 Andrew Vant 在 bpo-1926 中
贡献。）


certificates
------------

"http.client.HTTPSConnection"、"urllib.request.HTTPSHandler" 和
"urllib.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* 参数已被弃用。

"HTTPConnection" 和 "HTTPSConnection" 类现在有一个 *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 模块有许多改进，支持包的测试发现、在交互式提示符下更容易进行
实验、新的测试用例方法、改进的测试失败诊断消息以及更好的方法名称。

* 命令行调用 "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* 不是二的幂时存在轻微偏差。现在，
从下一个二的幂的范围中进行多次选择，并且只有当选择落在 "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('创建的临时目录：', 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('运行中')
     ...         return 10
     ...
     >>> a = A()
     >>> getattr(a, 'f')
     运行中
     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 安装版详细信息的函数。

* "getsitepackages()" 列出所有全局 site-packages 目录。

* "getuserbase()" 报告可用来存储数据的用户基准目录。

* "getusersitepackages()" 将揭示用户专属的 site-packages 目录路径。

   >>> 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" 模块使得发现依赖于不同系统平台和安装版的安装路径和
配置变量更为简单直观。

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

* "get_platform()" 将返回 *linux-i586* 或 *macosx-10.6-ppc* 形式的值。

* "get_python_version()" 将返回 Python 版本字符串如 "3.2"。

它还提供了与 "distutils" 所使用的七个规范名称所对应的路径和变量的访问
。 这包括 *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" 脚本文件可以包含 "continue" 和 "next" 命令，用于继续调
  试。

* "Pdb" 类构造函数现在接受一个 *nosigint* 参数。

* 新命令："l(list)"、"ll(long list)" 和 "source" 用于列出源代码。

* 新命令："display" 和 "undisplay" 用于显示或隐藏表达式值的变化。

* 新命令："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-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* 参数。如果是字符串，那么 *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'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-2987、bpo-5468
和 bpo-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
----------

"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 的窥孔优化器（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-9410 和 bpo-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 中贡献。）

* stringlib 中的快速搜索算法现在被 "bytes"、"bytearray" 和 "str" 对象
  的 "split()"、"rsplit()"、"splitlines()" 和 "replace()" 方法使用。同
  样，该算法也被 "rfind()"、"rindex()"、"rsplit()" 和 "rpartition()"
  方法使用。

  （由 Florent Xicluna 在 bpo-7622 和 bpo-7462 中提交补丁。）

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

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

还进行了其他一些小的优化。当一个操作数远大于另一个时，集合差分现在运行
得更快（由 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 个字符，包括对
手机重要的 emoji 符号。

此外，更新后的标准修改了两个卡纳达文字符（U+0CF1、U+0CF2）和一个新傣仂
数字字符（U+19DA）的字符属性：前者现在可用于标识符，而后者则不再符合标
识符使用要求。更多详细信息请参阅 Unicode字符数据库变更说明。


编解码器
========

添加了对 *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 中贡献。
  ）


代码库
======

除了现有的 Subversion 代码仓库位于 https://svn.python.org 外，现在还有
一个 Mercurial 仓库位于 https://hg.python.org/。

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

要学习使用新的版本控制系统，请参阅 快速入门 或 Mercurial工作流指南。


构建和 C API 的改变
===================

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

* 现在 *idle*、 *pydoc* 和 *2to3* 脚本的安装将在 "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 位长。得益于这一改进，"set" 和 "dict" 现在可以在使用 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)。

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

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://www.python.org/download/mac/tcltk/。


移植到 Python 3.2
=================

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

* "configparser" 模块进行了一系列清理工作。主要变化是将旧的
  "ConfigParser" 类替换为长期以来首选的替代类 "SafeConfigParser"。此外
  ，还有一些较小的兼容性问题：

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

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

  * 来自单个源的重复节或选项现在会引发 "DuplicateSectionError" 或
    "DuplicateOptionError"。此前，重复项会默默地覆盖先前的条目。

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

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

  * """" 现在是一个有效值，不再自动转换为空字符串。对于空字符串，请在
    行中使用 ""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*
  参数设置为 *1*，即 "random.seed(s, version=1)"。

* 此前已弃用的 "string.maketrans()" 函数已被移除，取而代之的是静态方法
  "bytes.maketrans()" 和 "bytearray.maketrans()"。这一变更解决了关于
  "string" 模块支持哪些数据类型的混淆问题。现在，"str"、"bytes" 和
  "bytearray" 类型各自拥有独立的 **maketrans** 和 **translate** 方法，
  并会生成与相应类型匹配的中间转换表。

  （由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()" 现在只允许使用字节类型（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.request" 和 "http.client" 中移除
  。 此项支持仍然存在于服务器端（在 "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()" 之前被调用。
