Python 3.2 的新特性 — Python 文档
Python 3.2 中的新功能
- 作者
- 雷蒙德·赫廷格
本文解释了 Python 3.2 与 3.1 相比的新特性。 它侧重于一些亮点并给出了一些示例。 有关完整详细信息,请参阅 杂项/新闻 文件。
PEP 384:定义稳定的 ABI
过去,为一个 Python 版本构建的扩展模块通常无法用于其他 Python 版本。 特别是在 Windows 上,Python 的每个功能版本都需要重新构建人们想要使用的所有扩展模块。 这个要求是免费访问扩展模块可以使用的 Python 解释器内部的结果。
在 Python 3.2 中,一种替代方法变得可用:将自身限制为有限 API(通过定义 Py_LIMITED_API)的扩展模块不能使用许多内部结构,而是被限制为一组承诺在多个版本中稳定的 API 函数。 因此,在该模式下为 3.2 构建的扩展模块也适用于 3.3、3.4 等。 仍然可以构建使用内存结构细节的扩展模块,但需要为每个功能版本重新编译。
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 3148:concurrent.futures 模块
用于创建和管理并发的代码被收集在一个新的顶级命名空间 concurrent 中。 它的第一个成员是 futures 包,它为管理线程和进程提供了统一的高级接口。
concurrent.futures 的设计灵感来自 java.util.concurrent 包。 在该模型中,正在运行的调用及其结果由 Future 对象表示,该对象抽象了线程、进程和远程过程调用共有的特征。 该对象支持状态检查(运行或完成)、超时、取消、添加回调以及访问结果或异常。
新模块的主要产品是一对用于启动和管理调用的执行程序类。 执行程序的目标是更容易地使用现有工具进行并行调用。 它们节省了设置资源池、启动调用、创建结果队列、添加超时处理以及限制线程、进程或远程过程调用的总数所需的工作。
理想情况下,每个应用程序应该跨多个组件共享一个执行器,以便可以集中管理进程和线程限制。 这解决了当每个组件都有自己的资源管理竞争策略时出现的设计挑战。
这两个类共享一个具有三个方法的公共接口: submit() 用于调度一个可调用对象并返回一个 Future 对象; map() 用于一次调度多个异步调用,shutdown() 用于释放资源。 该类是一个 上下文管理器 ,可以在 with 语句中使用,以确保在当前挂起的期货完成执行时自动释放资源。
ThreadPoolExecutor 的一个简单示例是启动四个用于复制文件的并行线程:
import concurrent.futures, shutil
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as e:
e.submit(shutil.copy, 'src1.txt', 'dest1.txt')
e.submit(shutil.copy, 'src2.txt', 'dest2.txt')
e.submit(shutil.copy, 'src3.txt', 'dest3.txt')
e.submit(shutil.copy, 'src3.txt', 'dest4.txt')
也可以看看
- PEP 3148 - Futures - 异步执行计算
- 布赖恩·昆兰 (Brian Quinlan) 撰写的 PEP。
线程并行URL读取代码,一个使用线程并行获取多个网页的示例。
并行计算素数的代码,一个演示ProcessPoolExecutor的例子。
PEP 3147:PYC 存储库目录
Python 在 .pyc 文件中缓存字节码的方案在具有多个 Python 解释器的环境中不能很好地工作。 如果一个解释器遇到另一个解释器创建的缓存文件,它会重新编译源文件并覆盖缓存文件,从而失去缓存的好处。
“pyc 冲突”的问题变得更加突出,因为 Linux 发行版随附多个 Python 版本已变得司空见惯。 这些冲突也出现在 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 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 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。 例如,使用 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 转码为原生字符串和返回一个新字典。
其他语言更改
对核心 Python 语言进行的一些较小更改是:
format() 和 str.format() 的字符串格式化获得了格式字符 # 的新功能。 以前,对于二进制、八进制或十六进制整数,它会导致输出分别以“0b”、“0o”或“0x”为前缀。 现在它还可以处理浮点数、复数和十进制数,即使后面没有数字,输出也总是有小数点。
>>> format(20, '#o') '0o24' >>> format(12.34, '#5.0f') ' 12.'
(由 Mark Dickinson 提出并由 Eric Smith 在 :issue:`7094` 中实现。)
还有一个新的 str.format_map() 方法,它通过接受任意 映射 对象来扩展现有 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 在 :issue:`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 在 :issue:`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 修复;:issue:`9666`。)
浮点数或复数的 str() 现在与其 repr() 相同。 以前, str() 形式更短,但这只会引起混乱,现在不再需要,因为默认情况下会显示尽可能短的 repr():
>>> import math >>> repr(math.pi) '3.141592653589793' >>> str(math.pi) '3.141592653589793'
(由 Mark Dickinson 提出并实现;:issue:`9337`。)
memoryview 对象现在有一个 release() 方法,它们现在也支持上下文管理协议。 这允许及时释放从原始对象请求缓冲区时获取的任何资源。
>>> with memoryview(b'abcdefgh') as v: ... print(v.tolist()) [97, 98, 99, 100, 101, 102, 103, 104]
(由 Antoine Pitrou 添加;:issue:`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
(参见 :issue:`4617`。)
内部
structsequence
工具现在创建元组的子类。 这意味着像 os.stat()、time.gmtime() 和 sys.version_info 返回的那些 C 结构现在像 一样工作命名为 tuple ,现在可以使用需要元组作为参数的函数和方法。 这是使 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 在 :issue:`8413` 中实现。)
现在使用 PYTHONWARNINGS 环境变量作为在命令行中使用
-W
的替代方法更容易控制警告:$ export PYTHONWARNINGS='ignore::RuntimeWarning::,once::UnicodeWarning::'
(由 Barry Warsaw 提出并由 Philip Jenvey 在 :issue:`7301` 中实现。)
添加了新的警告类别 ResourceWarning。 当检测到资源消耗或清理的潜在问题时会发出它。 默认情况下,它在正常发布版本中是静音的,但可以通过 warnings 模块提供的方法或在命令行上启用。
如果 gc.garbage 列表不为空,并且如果设置了 gc.DEBUG_UNCOLLECTABLE,则在解释器关闭时发出 ResourceWarning,则打印所有不可收集的对象。 这是为了让程序员意识到他们的代码包含对象终结问题。
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 在 :issue:`10093` 和 :issue:`477863` 中添加。)
range 对象现在支持 [X35X]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 在 :issue:`9213`、Alexander Belopolsky 在 :issue:`2690` 和 Nick Coghlan 在 :issue:`10889` 中贡献。)
来自 Py2.x 的 callable() 内置函数复活了。 它为在
isinstance(x, collections.Callable)
等表达式中使用 抽象基类 提供了一种简洁、易读的替代方法:>>> callable(max) True >>> callable(20) False
(参见 :issue:`10518`。)
Python 的导入机制现在可以加载安装在路径名中包含非 ASCII 字符的目录中的模块。 这解决了用户名中包含非 ASCII 字符的用户主目录的严重问题。
(需要 Victor Stinner 在 中进行大量工作:问题:`9425`。)
新的、改进的和弃用的模块
Python 的标准库经历了重大的维护工作和质量改进。
Python 3.2 的最大新闻是 email 包、mailbox 模块和 nntplib 模块现在可以与 Python 3 中的字节/文本模型一起正常工作。 这是第一次正确处理混合编码的消息。
在整个标准库中,人们更加关注编码和文本与字节问题。 特别是,与操作系统的交互现在能够更好地使用 Windows MBCS 编码、区域设置感知编码或 UTF-8 交换非 ASCII 数据。
另一个重大胜利是增加了对 SSL 连接和安全证书的更好的支持。
此外,现在更多的类实现了 上下文管理器 以支持使用 和 语句方便可靠的资源清理。
电子邮件
email 包在 Python 3 中的可用性主要由 R 的广泛努力修复。 大卫·默里。 问题在于,电子邮件通常以 字节 而非 str 文本的形式读取和存储,并且它们可能在一封电子邮件中包含多种编码。 因此,必须扩展电子邮件包以解析和生成字节格式的电子邮件消息。
新函数 message_from_bytes() 和 message_from_binary_file(),以及新类 BytesFeedParser 和 BytesParser 允许解析二进制消息模型数据对象.
给定字节输入模型,get_payload() 将默认使用在MIME 标头并返回结果字符串。
给定字节输入到模型中,Generator 会将具有 Content-Transfer-Encoding 为 8bit 的消息体转换为具有 7bit ] 内容传输编码。
带有未编码非 ASCII 字节的标头被视为使用 unknown-8bit 字符集 RFC 2047 编码。
新类 BytesGenerator 生成字节作为输出,保留用于构建模型的输入中存在的任何未更改的非 ASCII 数据,包括具有 Content-Transfer-Encoding 的消息体8bit。
smtplib SMTP 类现在接受 sendmail() 方法的 msg 参数的字节字符串,以及一个新方法 [ X150X]send_message() 接受一个 Message 对象,并且可以选择直接从对象中获取 from_addr 和 to_addrs 地址。
(由 R 提出并实施。 David Murray,:issue:`4661` 和 :issue:`10321`。)
元素树
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() 处理文档类型声明
两种方法已被弃用:
xml.etree.ElementTree.getchildren()
使用list(elem)
代替。xml.etree.ElementTree.getiterator()
使用Element.iter
代替。
有关更新的详细信息,请参阅 Fredrik Lundh 网站上的 Introducing ElementTree。
(由 Florent Xicluna 和 Fredrik Lundh 提供,:issue:`6472`。)
功能工具
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 的设计理念;参见 配方 498245、 配方 577479、:问题:`10586X ] 和 :issue:`10593`。)
functools.wraps() 装饰器现在添加了一个指向原始可调用函数的
__wrapped__
属性。 这允许内省包装的函数。 如果定义,它还复制__annotations__
。 现在它也优雅地跳过丢失的属性,例如__doc__
可能没有为包装的可调用对象定义。在上面的例子中,可以通过恢复原始函数来移除缓存:
>>> get_phone_number = get_phone_number.__wrapped__ # uncached function
(由 Nick Coghlan 和 Terrence Cole 撰写;:issue:`9567`、:issue:`3445` 和 :issue:`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 装饰器,自动填充剩余的比较方法。
(雷蒙德·赫廷格供稿。)
为了帮助从 Python 2 移植程序,functools.cmp_to_key() 函数将旧式比较函数转换为现代 key 函数 :
>>> # locale-aware sort order >>> sorted(iterable, key=cmp_to_key(locale.strcoll))
有关排序示例和简要排序教程,请参阅 Sorting HowTo 教程。
(雷蒙德·赫廷格供稿。)
迭代工具
itertools 模块有一个新的 accumulate() 函数,该函数以 APL 的 scan 运算符和 Numpy 的 accumulate 函数为模型:
>>> from itertools import accumulate >>> list(accumulate([8, 2, 50])) [8, 10, 60]
>>> prob_dist = [0.1, 0.4, 0.2, 0.3] >>> list(accumulate(prob_dist)) # cumulative probability distribution [0.1, 0.5, 0.7, 1.0]
有关使用 accumulate() 的示例,请参阅随机模块 的 示例。
(由 Raymond Hettinger 提供,并结合了 Mark Dickinson 的设计建议。)
收藏
collections.Counter 类现在有两种形式的就地减法,现有的 -= 运算符用于 饱和减法 和新的 subtract() 常规减法方法。 前者适用于只有正数的 multisets,后者更适用于允许负数的用例:
>>> 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})
(雷蒙德·赫廷格供稿。)
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']
(雷蒙德·赫廷格供稿。)
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'])
(雷蒙德·赫廷格供稿。)
穿线
threading 模块有一个新的 Barrier 同步类,用于让多个线程等待,直到所有线程都到达一个公共屏障点。 障碍对于确保具有多个先决条件的任务在所有前置任务完成之前不会运行非常有用。
Barriers 可以处理任意数量的线程。 这是仅为两个线程定义的 Rendezvous 的概括。
Barrier 对象实现为两阶段循环屏障,适用于循环。 单独的 filling 和 draining 阶段确保所有线程在它们中的任何一个可以循环并重新进入屏障之前被释放(排出)。 屏障在每个循环后完全重置。
使用障碍的例子:
from threading import Barrier, Thread
def get_votes(site):
ballots = conduct_election(site)
all_polls_closed.wait() # do not count until all polls are closed
totals = summarize(ballots)
publish(site, totals)
all_polls_closed = Barrier(len(sites))
for site in sites:
Thread(target=get_votes, args=(site,)).start()
在此示例中,屏障强制执行一项规则,即在所有投票关闭之前,不能在任何投票站点计算选票。 请注意带有屏障的解决方案如何类似于带有 threading.Thread.join() 的解决方案,但线程在越过屏障点后仍保持活动状态并继续工作(汇总选票)。
如果任何前置任务可能挂起或延迟,则可以使用可选的 timeout 参数创建屏障。 然后,如果在所有前驱任务到达屏障点之前超时时间已过,则所有等待线程都将被释放并引发 BrokenBarrierError 异常:
def get_votes(site):
ballots = conduct_election(site)
try:
all_polls_closed.wait(timeout=midnight - time.now())
except BrokenBarrierError:
lockbox = seal_ballots(ballots)
queue.put(lockbox)
else:
totals = summarize(ballots)
publish(site, totals)
在此示例中,屏障强制执行更稳健的规则。 如果某些选举地点在午夜前未完成,则屏障超时,选票将被密封并放入队列中以备稍后处理。
有关如何在并行计算中使用屏障的更多示例,请参阅 屏障同步模式 。 此外,在信号量小书,第3.6节中对障碍进行了简单而彻底的解释。
(由 Kristján Valur Jónsson 提供,Jeffrey Yasskin 在 :issue:`8777` 中进行了 API 审查。)
日期时间和时间
datetime 模块有一个新类型 timezone,它通过返回固定的 UTC 偏移量和时区名称来实现 tzinfo 接口。 这使得创建时区感知日期时间对象变得更加容易:
>>> 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
,这意味着对于两位数的年份,根据管理%y
strptime 格式的 POSIX 规则猜测世纪。从 Py3.2 开始,使用世纪猜测启发式将发出 DeprecationWarning。 相反,建议将
time.accept2dyear
设置为False
,以便可以使用大日期范围而无需猜测:>>> import time, warnings >>> warnings.resetwarnings() # remove the default warning filters >>> time.accept2dyear = True # guess whether 11 means 11 or 2011 >>> time.asctime((11, 1, 1, 12, 34, 56, 4, 1, 0)) Warning (from warnings module): ... DeprecationWarning: Century info guessed for a 2-digit year. 'Fri Jan 1 12:34:56 2011' >>> time.accept2dyear = False # use the full range of allowable dates >>> time.asctime((11, 1, 1, 12, 34, 56, 4, 1, 0)) 'Fri Jan 1 12:34:56 11'
现在有几个函数显着扩展了日期范围。 当
time.accept2dyear
为假时,time.asctime() 函数将接受适合 C int 的任何年份,而 time.mktime() 和 ]time.strftime() 函数将接受相应操作系统函数支持的完整范围。
(由 Alexander Belopolsky 和 Victor Stinner 在 中贡献:issue:`1289118`, :issue:`5094`, :issue:`6641`, ]:issue:`2706`, :issue:`1777412`, :issue:`8013`, and :issue:`10827` .)
数学
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() 函数用于计算 gamma 函数的自然对数:
>>> from math import gamma, lgamma
>>> gamma(7.0) # six factorial
720.0
>>> lgamma(801.0) # log(800 factorial)
4551.950730698041
(马克·狄金森供稿。)
美国广播公司
abc 模块现在支持 [X37X]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 提交的补丁;:issue:`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 在 中提供:issue:`5506`。)
复制库
在为自定义容器编写 __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 在 :issue:`9826` 和 :issue:`9840` 中贡献。)
日志记录
除了上述基于字典的配置外,logging 包还有许多其他改进。
日志文档增加了 基础教程 、 高级教程 和日志记录配方的 食谱 。 这些文档是了解日志记录的最快方式。
logging.basicConfig() 设置函数获得了一个 style 参数以支持三种不同类型的字符串格式。 对于传统的 % 格式,它默认为“%”,对于新的 str.format() 样式可以设置为“{”,或者对于提供的 shell 样式格式可以设置为“$”通过 string.Template。 以下三种配置是等效的:
>>> 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 指向 sys.stderr 的默认配置,用于 WARNING
级别的事件或更高。 以前,根据 logging.raiseExceptions
的值,在设置配置之前发生的事件会引发异常或静默删除该事件。 新的默认处理程序存储在 logging.lastResort 中。
过滤器的使用已得到简化。 谓词可以是任何返回 True
或 False
的 Python 可调用对象,而不是创建 Filter 对象。
还有许多其他改进可以增加灵活性并简化配置。 有关 Python 3.2 中更改的完整列表,请参阅模块文档。
文件
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 在 :issue:`5975` 中建议的新方言,以及 Ed Abraham 在 :issue:`1537721` 中建议的新方法。)
上下文库
有一个新的、有点令人兴奋的工具 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 在 中提供:issue:`9110`。)
小数和分数
马克·迪金森 (Mark Dickinson) 精心设计了一个优雅而有效的方案,以确保不同的数字数据类型在其实际值相等时将具有相同的哈希值 (:issue:`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() 方法 (:issue:` 8257`)。
- 现在完全支持混合类型比较,因此 Decimal 对象可以直接与 float 和 fractions.Fraction (:issue:`2531`[ X175X] 和 :问题:`8188`)。
对 fractions.Fraction 进行了类似的更改,因此不再需要 from_float() 和 from_decimal() 方法(:issue:`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 中指定的十进制交换格式相对应的上下文时很有用(请参阅 :issue:`8540`)。
(马克·迪金森和雷蒙德·赫廷格供稿。)
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à 在 :issue:`4972` 和 Georg Brandl 在 :issue:`8046` 和 :issue:`1286`[ X143X]。)
FTP_TLS 类现在接受 context 参数,这是一个 ssl.SSLContext 对象,允许将 SSL 配置选项、证书和私钥捆绑到一个(可能很长) -居住)结构。
(由 Giampaolo Rodolà 提供;:issue:`8806`。)
弹出
os.popen() 和 subprocess.Popen() 函数现在支持 with 语句来自动关闭文件描述符。
(由 Antoine Pitrou 和 Brian Curtin 在 :issue:`7461` 和 :issue:`10554` 中贡献。)
选择
select 模块现在公开了一个新的常量属性 PIPE_BUF,它给出了在 select.select() 时保证不会阻塞的最小字节数说一个管道已准备好写入。
>>> import select
>>> select.PIPE_BUF
512
(在 Unix 系统上可用。 Sébastien Sablé 在 中的补丁:问题:`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 in :issue:`3488`; 由 Antoine Pitrou、Nir Aides 和 Brian Curtin 在 :issue:`9962`、:issue:`1675951`、:issue:`7471` 和:问题:`2846`。)
此外,zipfile.ZipExtFile
类在内部进行了重新设计,以表示存储在存档中的文件。 新的实现速度明显更快,并且可以包装在 io.BufferedReader 对象中以获得更多加速。 它还解决了交错调用 read 和 readline 给出错误结果的问题。
(Nir Aides 在 中提交的补丁:问题:`7610`。)
tar文件
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 在 :issue:`6856` 中实现。)
哈希库
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 在 :issue:`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 模块提供了两个新函数,fsencode() 和 fsdecode(),用于对文件名进行编码和解码:
>>> import os
>>> filename = 'Sehenswürdigkeiten'
>>> os.fsencode(filename)
b'Sehensw\xc3\xbcrdigkeiten'
某些操作系统允许直接访问环境中的编码字节。 如果是这样,os.supports_bytes_environ 常量将为真。
要直接访问编码的环境变量(如果可用),请使用新的 os.getenvb() 函数或使用 os.environb 这是 os.environ 的字节版本。
(维克多·斯廷纳供稿。)
休蒂尔
shutil.copytree() 函数有两个新选项:
- ignore_dangling_symlinks:当
symlinks=False
时,函数复制符号链接指向的文件,而不是符号链接本身。 如果文件不存在,此选项将消除引发的错误。 - copy_function:是一个可调用的,用于复制文件。 shutil.copy2() 默认使用。
(由 Tarek Ziadé 提供。)
此外,shutil 模块现在支持 归档操作 用于 zip 文件、未压缩的 tarfile、gzipped tarfile 和 bzipped tarfile。 并且还有用于注册其他存档文件格式(例如 xz 压缩 tarfiles 或自定义格式)的功能。
主要函数是 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. 大卫·默里和沙什瓦特·阿南德; :问题:`8845`。)
html
引入了一个新的 html 模块,只有一个函数,escape(),用于从 HTML 标记中转义保留字符:
>>> import html
>>> html.escape('x > 2 && x < 7')
'x > 2 && x < 7'
插座
socket 模块有两个新的改进。
- 套接字对象现在有一个 detach() 方法,该方法将套接字置于关闭状态而不实际关闭底层文件描述符。 后者可以再用于其他目的。 (由 Antoine Pitrou 添加;:issue:`8524`。)
- socket.create_connection() 现在支持上下文管理协议无条件消耗 socket.error 异常并在完成时关闭套接字。 (由 Giampaolo Rodolà 提供;:issue:`9794`。)
ssl
ssl 模块添加了许多功能以满足安全(加密、认证)互联网连接的常见要求:
- 一个新类 SSLContext 用作持久性 SSL 数据的容器,例如协议设置、证书、私钥和各种其他选项。 它包括一个 wrap_socket(),用于从 SSL 上下文创建 SSL 套接字。
- 一个新函数 ssl.match_hostname(),通过实现 HTTPS 规则(来自 RFC 2818)支持更高级别协议的服务器身份验证,这些规则是也适用于其他协议。
- ssl.wrap_socket() 构造函数现在采用 ciphers 参数。 ciphers 字符串使用 OpenSSL 文档 中描述的格式列出了允许的加密算法。
- 当与最新版本的 OpenSSL 链接时,ssl 模块现在支持 TLS 协议的服务器名称指示扩展,允许多个“虚拟主机”在单个 IP 端口上使用不同的证书。 此扩展仅在客户端模式下受支持,并通过将 server_hostname 参数传递给 ssl.SSLContext.wrap_socket() 来激活。
- ssl 模块中添加了各种选项,例如 OP_NO_SSLv2 禁用不安全和过时的 SSLv2 协议。
- 该扩展现在加载所有 OpenSSL 密码和摘要算法。 如果某些 SSL 证书无法验证,则会报告为“未知算法”错误。
- 现在可以使用模块属性 ssl.OPENSSL_VERSION(字符串)、ssl.OPENSSL_VERSION_INFO(5 元组)和 ssl.OPENNUMBER_VERS 访问正在使用的 OpenSSL 版本(整数)。
(由 Antoine Pitrou 在 :issue:`8850`、:issue:`1589`、:issue:`8322`、:issue 中贡献:`5639`, :issue:`4870`, :issue:`8484`, 和 :issue:`8321`。)
ntp
nntplib 模块具有改进的实现,具有更好的字节和文本语义以及更实用的 API。 这些改进破坏了与 Python 3.1 中的 nntplib 版本的兼容性,这本身就部分功能失调。
还添加了通过隐式(使用 nntplib.NNTP_SSL)和显式(使用 nntplib.NNTP.starttls())TLS 对安全连接的支持。
(由 Antoine Pitrou 在 :issue:`9360` 和 Andrew Vant 在 :issue:`1926` 中贡献。)
证书
http.client.HTTPSConnection、urllib.request.HTTPSHandler 和 urllib.request.urlopen() 现在采用可选参数来允许对一组服务器证书进行检查证书颁发机构,如在 HTTPS 的公共使用中推荐的那样。
(由 Antoine Pitrou 添加,:issue:`9003`。)
映射库
通过新的 imaplib.IMAP4.starttls 方法添加了对标准 IMAP4 连接上的显式 TLS 的支持。
(洛伦佐 M. 供稿) Catucci 和 Antoine Pitrou,:问题:`4471`。)
客户端
http.client 模块中有许多小的 API 改进。 不再支持旧式 HTTP 0.9 简单响应,并且所有类中都弃用了 strict 参数。
HTTPConnection 和 HTTPSConnection 类现在有一个 source_address 参数用于(主机,端口)元组,指示 HTTP 连接的来源。
HTTPSConnection 添加了对证书检查和 HTTPS 虚拟主机的支持。
连接对象上的 request() 方法允许使用可选的 body 参数,以便 文件对象 可用于提供请求的内容。 方便的是, body 参数现在也接受 iterable 对象,只要它包含一个显式的 Content-Length
标头。 这个扩展接口比以前灵活得多。
为了通过代理服务器建立 HTTPS 连接,有一个新的 set_tunnel() 方法可以设置 HTTP Connect 隧道的主机和端口。
为了匹配 http.server 的行为,HTTP 客户端库现在还使用 ISO-8859-1 (Latin-1) 编码对标头进行编码。 它已经对传入的标头这样做了,所以现在传入和传出流量的行为都是一致的。 (参见 Armin Ronacher 在 :issue:`10980` 中的工作。)
单元测试
unittest 模块有许多改进,支持包的测试发现、在交互式提示下更容易的实验、新的测试用例方法、改进的测试失败诊断消息以及更好的方法名称。
命令行调用
python -m unittest
现在可以接受文件路径而不是模块名称来运行特定测试 (:issue:`10620`)。 新的测试发现可以在包中找到测试,定位任何可从顶级目录导入的测试。 可以使用 -t 选项指定顶级目录、与-p
匹配文件的模式以及使用-s
开始发现的目录:$ python -m unittest discover -s my_proj_dir -p _test.py
(迈克尔·福特供稿。)
现在可以更轻松地在交互式提示下进行实验,因为现在可以在没有参数的情况下实例化
unittest.case.TestCase
类:>>> from unittest import TestCase >>> TestCase().assertEqual(pow(2, 3), 8)
(迈克尔·福特供稿。)
unittest 模块有两个新方法,assertWarns() 和 assertWarnsRegex() 来验证给定的警告类型是否由被测代码触发:
with self.assertWarns(DeprecationWarning): legacy_function('XYZ')
(由 Antoine Pitrou 提供,:issue:`9754`。)
另一个新方法 assertCountEqual() 用于比较两个可迭代对象,以确定它们的元素计数是否相等(无论顺序如何,是否存在相同元素且出现次数相同):
def test_anagram(self): self.assertCountEqual('algorithm', 'logarithm')
(雷蒙德·赫廷格供稿。)
unittest 模块的一个主要特性是在测试失败时努力产生有意义的诊断。 在可能的情况下,故障与输出的差异一起记录。 这对于分析失败测试运行的日志文件特别有用。 但是,由于差异有时可能很大,因此有一个新的 maxDiff 属性来设置显示差异的最大长度。
此外,模块中的方法名称也进行了多次清理。
例如,assertRegex() 是
assertRegexpMatches()
的新名称,因为测试使用 re.search(),而不是 re.match( )。 使用正则表达式的其他方法现在使用简写形式“Regex”而不是“Regexp”命名——这与其他单元测试实现中使用的名称匹配,与 Python 的 re 模块的旧名称匹配,并且它具有明确的含义骆驼壳。(由 Raymond Hettinger 提供,由 Ezio Melotti 实施。)
为了提高一致性,一些长期存在的方法别名被弃用,取而代之的是首选名称:
旧名
首选名称
assert_()
assertEquals()
assertNotEquals()
assertAlmostEquals()
assertNotAlmostEquals()
同样,Python 3.1 中弃用的
TestCase.fail*
方法预计将在 Python 3.3 中删除。 另请参阅 unittest 文档中的 弃用别名 部分。(由 Ezio Melotti 提供;:issue:`9424`。)
assertDictContainsSubset()
方法已被弃用,因为它使用错误顺序的参数错误实现。 这造成了难以调试的错觉,其中TestCase().assertDictContainsSubset({'a':1, 'b':2}, {'a':1})
之类的测试将失败。(雷蒙德·赫廷格供稿。)
随机的
random 模块中的整数方法现在可以更好地生成均匀分布。 以前,他们使用 int(n*random())
计算选择,当 n 不是 2 的幂时,该选择会有轻微的偏差。 现在,从一个范围内进行多项选择,直到下一个 2 的幂,并且只有当它落在 0 <= x < n
范围内时才保留选择。 受影响的函数和方法是 randrange()、randint()、choice()、shuffle() 和 sample ()。
(由 Raymond Hettinger 提供;:issue:`9025`。)
流行库
POP3_SSL 类现在接受 context 参数,这是一个 ssl.SSLContext 对象,允许将 SSL 配置选项、证书和私钥捆绑到一个(可能是长住)结构。
(由 Giampaolo Rodolà 提供;:issue:`8807`。)
异步
asyncore.dispatcher 现在提供了一个 handle_accepted() 方法,返回一个 (sock, addr) 对,当实际与新远程建立连接时调用该对端点。 这应该用作旧的 handle_accept() 的替代品,并避免用户直接调用 accept()。
(由 Giampaolo Rodolà 提供;:issue:`6706`。)
临时文件
tempfile 模块有一个新的上下文管理器,TemporaryDirectory,它提供了对临时目录的简单确定性清理:
with tempfile.TemporaryDirectory() as tmpdirname:
print('created temporary dir:', tmpdirname)
(由 Neil Schemenauer 和 Nick Coghlan 提供;:issue:`5178`。)
检查
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 提供,:issue:`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>
(迈克尔·福特供稿。)
pydoc
pydoc 模块现在提供了一个大大改进的 Web 服务器界面,以及一个新的命令行选项 -b
以自动打开浏览器窗口以显示该服务器:
$ pydoc3.2 -b
(由 Ron Adam 提供;:issue:`2001`。)
迪斯
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 在 :issue:`9147` 中提供。)
地点
site 模块具有三个新函数,可用于报告给定 Python 安装的详细信息。
- getsitepackages() 列出所有全局站点包目录。
- getuserbase() 报告可以存储数据的用户基本目录。
- getusersitepackages() 显示用户特定的站点包目录路径。
>>> 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'
方便的是,可以直接从命令行访问站点的某些功能:
$ python -m site --user-base
/Users/raymondhettinger/.local
$ python -m site --user-site
/Users/raymondhettinger/.local/lib/python3.2/site-packages
(由 Tarek Ziadé 在 中提供:issue:`6693`。)
系统配置
新的 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]、X1 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.py
现在有一个-c
选项,可以执行.pdbrc
脚本文件中给出的命令。.pdbrc
脚本文件可以包含继续调试的continue
和next
命令。Pdb
类构造函数现在接受 nosigint 参数。- 新命令:
l(list)
、ll(long list)
和source
用于列出源代码。 - 新命令:
display
和undisplay
用于显示或隐藏已更改的表达式值。 - 新命令:
interact
用于启动包含在当前作用域中找到的全局和本地名称的交互式解释器。 - 断点可以通过断点号清除。
(由 Georg Brandl、Antonio Cuni 和 Ilya Sandler 提供。)
配置解析器
修改了 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('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 在 :issue:`2987`、:issue:`5468` 和 :issue:`9873`[ X125X]。)
邮箱
感谢 R 的共同努力。 David Murray,mailbox 模块已针对 Python 3.2 修复。 挑战在于邮箱最初设计为带有文本界面,但电子邮件最好用 字节 表示,因为消息的各个部分可能具有不同的编码。
该解决方案利用 email 包的二进制支持来解析任意电子邮件。 此外,该解决方案需要对 API 进行大量更改。
正如预期的那样,mailbox.Mailbox 对象的 add() 方法现在接受二进制输入。
StringIO 和文本文件输入已弃用。 此外,如果使用非 ASCII 字符,字符串输入将提前失败。 以前,当在后面的步骤中处理电子邮件时,它会失败。
还支持二进制输出。 get_file() 方法现在返回二进制模式的文件(它曾经错误地将文件设置为文本模式)。 还有一个新的 get_bytes() 方法,该方法返回对应于给定 键 的消息的 bytes 表示。
仍然可以使用旧 API 的 get_string() 方法获得非二进制输出,但这种方法不是很有用。 相反,最好从 Message 对象中提取消息或从二进制输入加载它们。
(由 R. David Murray,在 Steffen Daode Nrpmeso 的努力下,以及 Victor Stinner 在 :issue:`9124` 中的初始补丁。)
海龟演示
turtle 模块的演示代码从 Demo 目录移动到主库。 它包括十多个带有生动显示的示例脚本。 在 sys.path 上,现在可以直接从命令行运行:
$ python -m turtledemo
(从 Alexander Belopolsky 在 :issue:`10199` 中的 Demo 目录中移出。)
多线程
对并发运行的 Python 线程(通常称为 GIL 或全局解释器锁)的序列化执行的机制已被重写。 目标包括更可预测的切换间隔和由于锁争用和随后的系统调用数量而减少的开销。 允许线程切换的“检查间隔”概念已被放弃,取而代之的是以秒为单位的绝对持续时间。 此参数可通过 sys.setswitchinterval() 进行调整。 目前默认为 5 毫秒。
有关实现的其他详细信息可以从 python-dev 邮件列表消息 中读取(但是,此消息中公开的“优先级请求”并未保留以供包含)。
(由 Antoine Pitrou 提供。)
常规和递归锁现在接受一个可选的 timeout 参数到它们的 acquire() 方法。 (由 Antoine Pitrou 提供;:issue:`7316`。)
同样,threading.Semaphore.acquire() 也获得了一个 timeout 参数。 (由 Torsten Landschoff 提供;:issue:`850728`。)
现在可以通过使用 Pthreads 的平台上的信号中断常规和递归锁定获取。 这意味着在获取锁时出现死锁的 Python 程序可以通过向进程重复发送 SIGINT 来成功杀死(在大多数 shell 中通过按 Ctrl+C)。 (由 Reid Kleckner 提供;:issue:`8844`。)
优化
添加了许多小的性能增强:
Python 的窥孔优化器现在将
x in {1, 2, 3}
等模式识别为一组常量中的成员资格测试。 优化器将 set 重铸为 frozenset 并存储预先构建的常量。现在速度损失已经消失,开始使用集合表示法编写成员资格测试是可行的。 这种风格在语义上既清晰又快速:
extension = name.rpartition('.')[2] if extension in {'xml', 'html', 'xhtml', 'css'}: handle(name)
(Dave Malcolm 提供的补丁和其他测试;:issue:`6690`)。
使用 pickle 模块序列化和反序列化数据现在快了数倍。
(由 Alexandre Vassalotti、Antoine Pitrou 和 Unladen Swallow 团队在 :issue:`9410` 和 :issue:`3873` 中提供。)
list.sort() 和 sorted() 中使用的 Timsort 算法 现在运行速度更快,使用 键函数 调用时使用更少的内存]。 以前,列表的每个元素都用一个临时对象包装,该对象记住与每个元素关联的键值。 现在,两个键和值数组并行排序。 这节省了排序包装器消耗的内存,并节省了委托比较所损失的时间。
(Daniel Stutzbach 在 中的补丁:问题:`9915`。)
JSON 解码性能得到改进并减少内存消耗,只要为多个键重复相同的字符串。 此外,当
sort_keys
参数为真时,JSON 编码现在使用 C 加速。(由 Antoine Pitrou 在 :issue:`7451` 和 Raymond Hettinger 和 Antoine Pitrou 在 :issue:`10314` 中贡献。)
递归锁(使用 threading.RLock() API 创建)现在受益于 C 实现,这使它们与常规锁一样快,并且比以前的纯 Python 实现快 10 到 15 倍。
(由 Antoine Pitrou 提供;:issue:`3001`。)
stringlib 中的快速搜索算法现在被
split()
、rsplit()
、splitlines()
和replace()
方法在 bytes、[ X131X]bytearray 和 str 对象。 同样,该算法也被rfind()
、rindex()
、rsplit()
和rpartition()
使用。(Florent Xicluna 在 :issue:`7622` 和 :issue:`7462` 中的补丁。)
整数到字符串的转换现在一次处理两个“数字”,减少了除法和模运算的次数。
(:issue:`6713` 作者:Gawain Bolton、Mark Dickinson 和 Victor Stinner。)
还有其他几个小的优化。 当一个操作数比另一个操作数大得多时,集合差分现在运行得更快(Andress Bennetts 在 :issue:`8685` 中的补丁)。 array.repeat()
方法的实现速度更快(:issue:`1569291` by Alexander Belopolsky)。 BaseHTTPRequestHandler
具有更高效的缓冲(:issue:`3709` by Andrew Schaaf)。 operator.attrgetter() 函数已被加速(:issue:`10160` by Christos Georgiou)。 ConfigParser
加载多行参数的速度更快(:issue:`7113` by Łukasz Langa)。
统一码
Python 已更新为 Unicode 6.0.0。 该标准的更新增加了 2,000 多个新字符,包括对手机很重要的 emoji 符号。
此外,更新后的标准更改了两个卡纳达字符(U+0CF1、U+0CF2)和一个新太略数字字符(U+19DA)的字符属性,使前者有资格在标识符中使用,而后者则被取消资格。 有关详细信息,请参阅 Unicode 字符数据库更改 。
编解码器
添加了对 cp720 阿拉伯语 DOS 编码的支持 (:issue:`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 模块文档在顶部有一个快速链接,标记为:
(由 Raymond Hettinger 提供;参见 基本原理。)
文档现在包含更多示例和食谱。 特别是,re 模块有一个扩展部分,Regular Expression Examples。 同样,itertools 模块继续更新为新的 Itertools Recipes。
datetime 模块现在有一个纯 Python 的辅助实现。 没有更改任何功能。 这只是提供了一个更易于阅读的替代实现。
(由 Alexander Belopolsky 在 :issue:`9528` 中贡献。)
未维护的
Demo
目录已被删除。 一些演示被集成到文档中,一些被移动到Tools/demo
目录,其他的被完全删除。(由 Georg Brandl 在 中提供:issue:`7962`。)
空闲
格式菜单现在有一个选项可以通过去除尾随空格来清理源文件。
(由 Raymond Hettinger 提供;:issue:`5150`。)
Mac OS X 上的 IDLE 现在适用于 Carbon AquaTk 和 Cocoa AquaTk。
(由 Kevin Walzer、Ned Deily 和 Ronald Oussoren 提供;:issue:`6075`。)
代码库
除了 http://svn.python.org 上现有的 Subversion 代码存储库之外,现在 https://hg.python.org/ 上还有一个 Mercurial 存储库。
在 3.2 版本之后,有计划切换到 Mercurial 作为主要存储库。 这个分布式版本控制系统应该让社区成员更容易创建和共享外部变更集。 有关详细信息,请参阅 PEP 385。
要学习使用新版本控制系统,请参阅 快速入门 或 Mercurial 工作流指南 。
构建和 C API 更改
Python 构建过程和 C API 的更改包括:
idle、pydoc 和 2to3 脚本现在安装在
make altinstall
(:issue:`10679 `)。访问 Unicode 数据库的 C 函数现在接受和返回来自完整 Unicode 范围的字符,即使在窄的 unicode 构建(Py_UNICODE_TOLOWER、Py_UNICODE_ISDECIMAL 等)上也是如此。 Python 中的一个明显区别是 unicodedata.numeric() 现在返回大代码点的正确值,而 repr() 可能会将更多字符视为可打印的。
(由 Bupjoe Lee 报告并由 Amaury Forgeot D'Arc 修复;:问题:`5127`。)
现在默认情况下在支持的编译器上启用计算 goto(由配置脚本检测到)。 它们仍然可以通过指定
--without-computed-gotos
有选择地禁用。(由 Antoine Pitrou 提供;:issue:`9203`。)
选项
--with-wctype-functions
已删除。 内置的 unicode 数据库现在用于所有功能。(由 Amaury Forgeot D'Arc 提供;:issue:`9210`。)
散列值现在是一种新类型的值,
Py_hash_t
,它被定义为与指针具有相同的大小。 以前它们是 long 类型,在一些 64 位操作系统上它仍然只有 32 位长。 作为此修复的结果,set 和 dict 现在可以在具有 64 位指针的构建中保存多个2**32
条目(以前,它们可以增长到那个大小但它们的性能却出现了灾难性的下降)。(由 Raymond Hettinger 建议并由 Benjamin Peterson 实施;:issue:`9778`。)
一个新的宏
Py_VA_COPY
复制变量参数列表的状态。 它等效于 C99 va_copy,但可用于所有 Python 平台(:issue:`2443`)。新的 C API 函数 PySys_SetArgvEx() 允许嵌入式解释器设置 sys.argv 而无需修改 sys.path (:issue:`5753 `)。
PyEval_CallObject
现在仅以宏形式提供。 出于向后兼容性原因而保留的函数声明现在已删除 - 该宏于 1997 年引入(:issue:`8276`)。有一个新函数 PyLong_AsLongLongAndOverflow() 类似于 PyLong_AsLongAndOverflow()。 它们都用于将 Python int 转换为原生固定宽度类型,同时提供转换不适合的情况的检测 (:issue:`7767`)。
PyUnicode_CompareWithASCIIString() 函数现在返回 not equal 如果 Python 字符串是 NUL 终止。
有一个新函数 PyErr_NewExceptionWithDoc() 类似于 PyErr_NewException() 但允许指定文档字符串。 这让 C 异常具有与其纯 Python 对应物相同的自记录功能(:issue:`7033`)。
当使用
--with-valgrind
选项编译时,pymalloc 分配器在 Valgrind 下运行时将自动禁用。 这改进了在 Valgrind 下运行时的内存泄漏检测,同时在其他时间利用 pymalloc (:issue:`2422`)。从 PyArg_Parse 函数中删除了
O?
格式。 该格式不再使用,也从未被记录在案 (:issue:`8837`)。
C-API 还进行了许多其他小的更改。 有关完整列表,请参阅 :source:`Misc/NEWS` 文件。
此外,Mac OS X 版本也有许多更新,有关详细信息,请参阅 :source:`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 模块进行了大量清理。 主要的变化是用长期首选的替代品
SafeConfigParser
替换旧的ConfigParser
类。 此外,还有一些较小的不兼容性:现在在 get() 和 set() 操作上验证插值语法。 在默认的插值方案中,只有两个带有百分号的标记是有效的:
%(name)s
和%%
,后者是一个转义的百分号。set() 和 add_section() 方法现在验证值是否为实际字符串。 以前,可能会无意中引入不受支持的类型。
来自单一来源的重复部分或选项现在会引发 DuplicateSectionError 或 DuplicateOptionError。 以前,重复项会默默地覆盖以前的条目。
现在默认禁用内联注释,因此现在可以安全地在值中使用 ; 字符。
评论现在可以缩进了。 因此,要使 ; 或 # 出现在多行值的行首,则必须对其进行插值。 这可以防止值中的注释前缀字符被误认为是注释。
""
现在是一个有效值,不再自动转换为空字符串。 对于空字符串,在一行中使用"option ="
。
nntplib 模块进行了广泛的重新设计,这意味着它的 API 通常与 3.1 API 不兼容。
为清晰起见,
array.tostring()
和array.fromstring()
已重命名为array.tobytes()
和array.frombytes()
。 旧名称已被弃用。 (参见 :issue:`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 提供;:问题:`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 修复;:问题:`10783`。)
xml.etree.ElementTree 类现在在解析失败时引发 xml.etree.ElementTree.ParseError。 以前它引发了 xml.parsers.expat.ExpatError。
浮点数上新的更长的 str() 值可能会破坏依赖于旧输出格式的文档测试。
在 subprocess.Popen 中,close_fds 的默认值现在在 Unix 下是
True
; 在Windows下,如果三个标准流设置为None
,则为True
,否则为False
。 以前,close_fds 默认总是False
,当打开的文件描述符泄漏到子进程时,这会产生难以解决的错误或竞争条件。已从 urllib.request 和 http.client 中删除对旧版 HTTP 0.9 的支持。 这种支持仍然存在于服务器端(在 http.server 中)。
(由 Antoine Pitrou 提供,:issue:`10711`。)
超时模式下的 SSL 套接字现在会在发生超时时引发 socket.timeout,而不是通用的 SSLError。
(由 Antoine Pitrou 提供,:issue:`10272`。)
误导性函数 PyEval_AcquireLock() 和 PyEval_ReleaseLock() 已被正式弃用。 应改用线程状态感知 API(例如 PyEval_SaveThread() 和 PyEval_RestoreThread())。
由于安全风险,
asyncore.handle_accept()
已被弃用,并添加了一个新功能asyncore.handle_accepted()
来替代它。(由 Giampaolo Rodola 在 中提供:issue:`6706`。)
由于新的 GIL 实现,在 Py_Initialize() 之前不能再调用 PyEval_InitThreads()。