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
PEP 由 Martin von Löwis 撰写。
PEP 389: Argparse 命令行解析模块¶
引入了一个新的命令行解析模块 argparse
,以克服 optparse
的限制,后者不支持位置参数(不仅仅是选项)、子命令、必需选项以及其他常见的指定和验证选项的模式。
作为第三方模块,该模块已在社区中取得了广泛成功。与它的前身相比,argparse
模块功能更全面,现在是命令行处理的首选模块。旧模块仍然可用,因为它依赖于大量的旧代码。
这是一个带注释的解析器示例,展示了以下功能:将结果限制到一组选择、在帮助屏幕中指定 metavar 、验证一个或多个位置参数是否存在,以及创建一个必需选项。
import argparse
parser = argparse.ArgumentParser(
description = 'Manage servers', # main description for help
epilog = 'Tested on Solaris and Linux') # displayed after help
parser.add_argument('action', # argument name
choices = ['deploy', 'start', 'stop'], # three allowed values
help = 'action on each target') # help msg
parser.add_argument('targets',
metavar = 'HOSTNAME', # var name used in help msg
nargs = '+', # require one or more targets
help = 'url for target machines') # help msg explanation
parser.add_argument('-u', '--user', # -u or --user option
required = True, # make it a required argument
help = 'login as user')
在命令字符串上调用解析器的示例。
>>> cmd = 'deploy sneezy.example.com sleepy.example.com -u skycaptain'
>>> result = parser.parse_args(cmd.split())
>>> result.action
'deploy'
>>> result.targets
['sneezy.example.com', 'sleepy.example.com']
>>> result.user
'skycaptain'
解析器自动生成的帮助示例。
>>> parser.parse_args('-h'.split())
usage: manage_cloud.py [-h] -u USER
{deploy,start,stop} HOSTNAME [HOSTNAME ...]
Manage servers
positional arguments:
{deploy,start,stop} action on each target
HOSTNAME url for target machines
optional arguments:
-h, --help show this help message and exit
-u USER, --user USER login as user
Tested on Solaris and Linux
argparse
的一个特别好的功能是能够定义子解析器,每个子解析器都有自己的参数模式和帮助显示。
import argparse
parser = argparse.ArgumentParser(prog='HELM')
subparsers = parser.add_subparsers()
parser_l = subparsers.add_parser('launch', help='Launch Control') # first subgroup
parser_l.add_argument('-m', '--missiles', action='store_true')
parser_l.add_argument('-t', '--torpedos', action='store_true')
parser_m = subparsers.add_parser('move', help='Move Vessel', # second subgroup
aliases=('steer', 'turn')) # equivalent names
parser_m.add_argument('-c', '--course', type=int, required=True)
parser_m.add_argument('-s', '--speed', type=int, default=0)
$ ./helm.py --help # top level help (launch and move)
$ ./helm.py launch --help # help for launch options
$ ./helm.py launch --missiles # set missiles=True and torpedos=False
$ ./helm.py steer --course 180 --speed 5 # set movement parameters
PEP 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
语句中使用,以确保在当前待处理的 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 – 异步执行计算
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
模块已更新,其中包含用于加载字节码文件的新 抽象基类。过时的 ABC,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') # find the version tag
'cpython-32mu'
>>> sysconfig.get_config_var('EXT_SUFFIX') # find the full filename extension
'.cpython-32mu.so'
参见
- PEP 3149 - ABI 版本标记的 .so 文件
PEP 由 Barry Warsaw 撰写。
PEP 3333: Python Web 服务器网关接口 v1.0.1¶
此信息性 PEP 阐明了 WSGI 协议如何处理字节/文本问题。挑战在于 Python 3 中的字符串处理最方便地使用 str
类型,尽管 HTTP 协议本身是面向字节的。
该 PEP 区分了用于请求/响应头和元数据的所谓 原生字符串 与用于请求和响应主体的 字节字符串。
原生字符串 始终是 str
类型,但仅限于 U+0000 到 U+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()
,用于将 os.environ
中的 CGI 变量转码为原生字符串并返回一个新的字典。
参见
- 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()
方法,它通过接受任意 映射 对象来扩展现有str.format()
方法的功能。这种新方法使得可以使用 Python 众多字典类对象(例如defaultdict
、Shelf
、ConfigParser
或dbm
)进行字符串格式化。它对于在查找之前规范化键或为未知键提供__missing__()
方法的自定义dict
子类也很有用:>>> 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() # implicit "del e" here
(参见 bpo-4617。)
结构序列类型 现在是元组的子类。这意味着 C 结构,例如由
os.stat()
、time.gmtime()
和sys.version_info
返回的那些,现在像 命名元组 一样工作,并且现在可以与期望元组作为参数的函数和方法一起工作。这是使 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 中贡献。)
Py2.x 中的内置函数
callable()
被恢复了。它提供了一种简洁、可读的替代方法,用于在像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
文本的形式读取和存储,并且它们可能在单个电子邮件中包含多种编码。因此,必须扩展 email 包以字节格式解析和生成电子邮件消息。
新函数
message_from_bytes()
和message_from_binary_file()
,以及新类BytesFeedParser
和BytesParser
允许将二进制消息数据解析为模型对象。给定模型的字节输入,如果消息正文的 Content-Transfer-Encoding 为 8bit,则
get_payload()
默认会使用 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 地址。
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.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)
如果电话列表表已更新,可以使用以下方法清除缓存中过时的内容:
>>> 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__ 和 __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))
有关排序示例和简短排序教程,请参阅 Sorting HowTo 教程。
(由 Raymond Hettinger 贡献。)
itertools¶
itertools
模块有一个新的accumulate()
函数,它模仿了 APL 的 scan 运算符和 Numpy 的 accumulate 函数:>>> from itertools import accumulate >>> list(accumulate([8, 2, 50])) [8, 10, 60]
>>> prob_dist = [0.1, 0.4, 0.2, 0.3] >>> list(accumulate(prob_dist)) # cumulative probability distribution [0.1, 0.5, 0.7, 1.0]
有关使用
accumulate()
的示例,请参阅 random 模块的示例。(由 Raymond Hettinger 贡献,并结合了 Mark Dickinson 的设计建议。)
collections¶
collections.Counter
类现在有两种形式的原地减法,现有的 -= 运算符用于 饱和减法,以及新的subtract()
方法用于常规减法。前者适用于只有正计数的 多重集,后者更适用于允许负计数的使用场景:>>> from collections import Counter >>> tally = Counter(dogs=5, cats=3) >>> tally -= Counter(dogs=2, cats=8) # saturating subtraction >>> tally Counter({'dogs': 3})
>>> tally = Counter(dogs=5, cats=3) >>> tally.subtract(dogs=2, cats=8) # regular subtraction >>> tally Counter({'dogs': 3, 'cats': -5})
(由 Raymond Hettinger 贡献。)
collections.OrderedDict
类有一个新方法move_to_end()
,它接受一个现有键并将其移动到有序序列的第一个或最后一个位置。默认是将项目移动到最后一个位置。这相当于使用
od[k] = od.pop(k)
续订条目。快速的移至末尾操作对于重新排序条目很有用。例如,有序字典可以用于通过使条目从最旧到最近访问来跟踪访问顺序。
>>> from collections import OrderedDict >>> d = OrderedDict.fromkeys(['a', 'b', 'X', 'd', 'e']) >>> list(d) ['a', 'b', 'X', 'd', 'e'] >>> d.move_to_end('X') >>> list(d) ['a', 'b', 'd', 'e', 'X']
(由 Raymond Hettinger 贡献。)
collections.deque
类新增了两个方法count()
和reverse()
,使其更接近list
对象的替代品:>>> from collections import deque >>> d = deque('simsalabim') >>> d.count('s') 2 >>> d.reverse() >>> d deque(['m', 'i', 'b', 'a', 'l', 'a', 's', 'm', 'i', 's'])
(由 Raymond Hettinger 贡献。)
threading¶
threading
模块有一个新的 Barrier
同步类,用于使多个线程等待所有线程都达到一个共同的屏障点。屏障对于确保具有多个前提条件的任务在所有前置任务完成之前不运行很有用。
屏障可以与任意数量的线程一起工作。这是 会合点 的泛化,后者仅适用于两个线程。
作为两阶段循环屏障实现,Barrier
对象适合在循环中使用。独立的 填充 和 排出 阶段确保所有线程在任何一个线程循环返回并重新进入屏障之前都被释放(排出)。每个循环后屏障完全重置。
使用屏障的示例:
from threading import Barrier, Thread
def get_votes(site):
ballots = conduct_election(site)
all_polls_closed.wait() # do not count until all polls are closed
totals = summarize(ballots)
publish(site, totals)
all_polls_closed = Barrier(len(sites))
for site in sites:
Thread(target=get_votes, args=(site,)).start()
在此示例中,屏障强制执行以下规则:在所有投票站关闭之前,不得在任何投票站计票。请注意,使用屏障的解决方案与使用 threading.Thread.join()
的解决方案类似,但线程在屏障点之后仍然存活并继续工作(汇总选票)。
如果任何前置任务可能挂起或延迟,则可以创建一个带可选 timeout 参数的屏障。然后,如果在所有前置任务到达屏障点之前超时期限已过,则所有等待线程都将被释放,并引发 BrokenBarrierError
异常:
def get_votes(site):
ballots = conduct_election(site)
try:
all_polls_closed.wait(timeout=midnight - time.now())
except BrokenBarrierError:
lockbox = seal_ballots(ballots)
queue.put(lockbox)
else:
totals = summarize(ballots)
publish(site, totals)
在这个例子中,屏障强制执行更严格的规则。如果某些选举站点在午夜之前未完成,则屏障超时,选票将被封存并存入队列中以供以后处理。
有关如何在并行计算中使用屏障的更多示例,请参阅 Barrier Synchronization Patterns。此外,在 The Little Book of Semaphores 的 3.6 节 中,对屏障有简单而全面的解释。
(由 Kristján Valur Jónsson 贡献,API 审查由 Jeffrey Yasskin 在 bpo-8777 中完成。)
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() # 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-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()
函数计算小 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 的内置对象,如 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'>
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")
如果在日志事件发生之前没有进行任何配置,现在会有一个默认配置,使用一个指向 sys.stderr
的 StreamHandler
,用于 WARNING
级别或更高级别的事件。以前,在配置设置之前发生的事件会根据 logging.raiseExceptions
的值引发异常或默默丢弃事件。新的默认处理程序存储在 logging.lastResort
中。
过滤器的使用已简化。现在,谓词可以是任何返回 True
或 False
的 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')
,因为后者在构建二进制浮点数时会丢失信息。然而,由于现有的浮点值可以无损地转换为十进制或有理数表示,因此将它们添加到构造函数并支持混合类型比较是有意义的。
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()
方法,并支持不可查找和零填充的文件对象。
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(): # 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 将 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
模块现在支持 zipfile、未压缩 tarfile、gzipped tarfile 和 bzipped tarfile 的归档操作。并且有函数用于注册额外的归档文件格式(例如 xz 压缩的 tarfile 或自定义格式)。
主要函数是 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。它有两个新功能。
如果存在未提交更改的活动事务,
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 > 2 && x < 7'
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 证书无法验证,则报告为“未知算法”错误。
正在使用的 OpenSSL 版本现在可以通过模块属性
ssl.OPENSSL_VERSION
(字符串)、ssl.OPENSSL_VERSION_INFO
(5 元组)和ssl.OPENSSL_VERSION_NUMBER
(整数)访问。
(由 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 中贡献。)
证书¶
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 连接来自何处的(主机,端口)元组。
证书检查和 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_()
assertEquals()
assertNotEquals()
assertAlmostEquals()
assertNotAlmostEquals()
同样,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 安装的详细信息。
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"
(由 Tarek Ziadé 从 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 函数指定回退值,或者直接从字典和字符串读取。
(所有更改均由 Ł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-2987、bpo-5468 和 bpo-9873 中完成。)
邮箱¶
感谢 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 在 bpo-10199 中从 Demo 目录移出。)
多线程¶
用于串行化并发运行的 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-9410 和 bpo-3873 中贡献。)
list.sort()
和sorted()
中使用的 Timsort 算法在调用时带有 key function,现在运行更快,使用的内存更少。以前,列表的每个元素都被一个临时对象包装,该对象记住了与每个元素关联的键值。现在,两个键和值数组并行排序。这节省了排序包装器消耗的内存,并节省了委托比较所浪费的时间。(Daniel Stutzbach 在 bpo-9915 中提交的补丁。)
当相同的字符串重复用于多个键时,JSON 解码性能得到提高,内存消耗减少。此外,当
sort_keys
参数为真时,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()
方法用于bytes
、bytearray
和str
对象。同样,该算法也用于rfind()
、rindex()
、rsplit()
和rpartition()
。整数到字符串的转换现在一次处理两个“数字”,减少了除法和模运算的次数。
(由 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 多个新字符,包括对手机至关重要的 表情符号。
此外,更新后的标准更改了两个卡纳达语字符 (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¶
代码仓库¶
除了现有的 Subversion 代码仓库 https://svn.python.org 之外,现在还有一个 Mercurial 仓库,地址是 https://hg.python.org/。
3.2 版本发布后,计划将主要仓库切换到 Mercurial。这个分布式版本控制系统应该能让社区成员更容易创建和共享外部变更集。有关详细信息,请参阅 PEP 385。
要学习使用新版本控制系统,请参阅快速入门或Mercurial工作流指南。
构建和 C API 更改¶
Python 的构建过程和 C API 的更改包括
在执行
make altinstall
时,idle、pydoc和2to3脚本现在会安装一个带有版本特定后缀的文件(bpo-10679)。即使在窄字符unicode构建(Py_UNICODE_TOLOWER、Py_UNICODE_ISDECIMAL等)上,访问Unicode数据库的C函数现在也接受并返回完整Unicode范围内的字符。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位操作系统上仍然只有32位长。由于此修复,在具有64位指针的构建中,set
和dict
现在可以容纳超过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()
。它们都用于将Pythonint
转换为原生定长类型,同时检测转换是否溢出(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://pythonlang.cn/download/mac/tcltk/。
移植到Python 3.2¶
本节列出以前描述的更改以及可能需要更改您的代码的其他错误修复
configparser
模块进行了多项清理。主要更改是将旧的ConfigParser
类替换为长期首选的替代方案SafeConfigParser
。此外,还有一些较小的兼容性问题现在,在
get()
和set()
操作期间,插值语法会进行验证。在默认插值方案中,只有两个带有百分号的标记有效:%(name)s
和%%
,后者是转义的百分号。set()
和add_section()
方法现在验证值是否为实际字符串。以前,可能会无意中引入不受支持的类型。来自单个源的重复节或选项现在会引发
DuplicateSectionError
或DuplicateOptionError
。以前,重复项会静默覆盖之前的条目。内联注释现在默认禁用,因此 ; 字符现在可以安全地用于值中。
注释现在可以缩进。因此,对于多行值中行首的 ; 或 #,必须进行插值。这可以防止值中的注释前缀字符被误认为是注释。
""
现在是一个有效值,不再自动转换为一个空字符串。对于空字符串,请在一行中使用"option ="
。
nntplib
模块经过了大量重构,这意味着其 API 通常与 3.1 API 不兼容。array.tostring()
和array.fromstring()
为清晰起见已分别更名为array.tobytes()
和array.frombytes()
。旧名称已被弃用。(参见bpo-8990。)PyArg_Parse*()
函数“t#”格式已删除:请改用“s#”或“s*”
“w”和“w#”格式已删除:请改用“w*”
在3.1中已弃用的
PyCObject
类型已删除。要将不透明的C指针包装到Python对象中,应改用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()
现在只允许使用字节作为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
,这会导致打开的文件描述符泄漏到子进程中,从而产生难以解决的错误或竞争条件。对传统 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()
之前调用。