Python 3.8 的新特性¶
- 编辑:
Raymond Hettinger
本文介绍了 Python 3.8 相较于 3.7 的新特性。Python 3.8 于 2019 年 10 月 14 日发布。有关完整详细信息,请参阅变更日志。
摘要 – 版本亮点¶
新特性¶
赋值表达式¶
新的语法 :=
可以在更大的表达式中将值赋给变量。由于它与海象的眼睛和牙齿相似,因此它被亲切地称为 “海象运算符”。
在此示例中,赋值表达式有助于避免两次调用 len()
if (n := len(a)) > 10:
print(f"List is too long ({n} elements, expected <= 10)")
在正则表达式匹配期间,也会出现类似的好处,此时需要两次匹配对象,一次用于测试是否发生匹配,另一次用于提取子组
discount = 0.0
if (mo := re.search(r'(\d+)% discount', advertisement)):
discount = float(mo.group(1)) / 100.0
该运算符在 while 循环中也很有用,这些循环计算一个值以测试循环终止,然后在循环体中再次需要该值
# Loop over fixed length blocks
while (block := f.read(256)) != '':
process(block)
另一个有用的用例出现在列表推导式中,其中在过滤条件中计算的值也需要在表达式主体中使用
[clean_name.title() for name in names
if (clean_name := normalize('NFC', name)) in allowed_names]
尝试将海象运算符的使用限制在减少复杂性并提高可读性的简洁情况下。
有关完整说明,请参阅 PEP 572。
(由 Emily Morehouse 在 bpo-35224 中贡献。)
仅限位置参数¶
有一个新的函数参数语法 /
,用于指示某些函数参数必须按位置指定,并且不能用作关键字参数。这与 help()
为使用 Larry Hastings 的 Argument Clinic 工具注释的 C 函数显示的表示法相同。
在以下示例中,参数 a 和 b 是仅限位置的,而 c 或 d 可以是位置或关键字,e 或 f 必须是关键字
def f(a, b, /, c, d, *, e, f):
print(a, b, c, d, e, f)
以下是有效的调用
f(10, 20, 30, d=40, e=50, f=60)
但是,这些是无效的调用
f(10, b=20, c=30, d=40, e=50, f=60) # b cannot be a keyword argument
f(10, 20, 30, 40, 50, f=60) # e must be a keyword argument
此表示法的一个用例是,它允许纯 Python 函数完全模拟现有 C 编码函数的行为。例如,内置的 divmod()
函数不接受关键字参数
def divmod(a, b, /):
"Emulate the built in divmod() function"
return (a // b, a % b)
另一个用例是在参数名称没有帮助时排除关键字参数。例如,内置的 len()
函数的签名是 len(obj, /)
。这避免了诸如此类的尴尬调用
len(obj='hello') # The "obj" keyword argument impairs readability
将参数标记为仅限位置的另一个好处是,它允许将来更改参数名称,而不会有破坏客户端代码的风险。例如,在 statistics
模块中,参数名称 dist 将来可能会更改。这是通过以下函数规范实现的
def quantiles(dist, /, *, n=4, method='exclusive')
...
由于 /
左侧的参数不会作为可能的关键字公开,因此参数名称仍可在 **kwargs
中使用
>>> def f(a, b, /, **kwargs):
... print(a, b, kwargs)
...
>>> f(10, 20, a=1, b=2, c=3) # a and b are used in two ways
10 20 {'a': 1, 'b': 2, 'c': 3}
这大大简化了需要接受任意关键字参数的函数和方法的实现。例如,这是 collections
模块中代码的摘录
class Counter(dict):
def __init__(self, iterable=None, /, **kwds):
# Note "iterable" is a possible keyword argument
有关完整说明,请参阅 PEP 570。
(由 Pablo Galindo 在 bpo-36540 中贡献。)
编译字节码文件的并行文件系统缓存¶
新的 PYTHONPYCACHEPREFIX
设置(也可作为 -X
pycache_prefix
提供)配置隐式字节码缓存以使用单独的并行文件系统树,而不是每个源目录中的默认 __pycache__
子目录。
缓存的位置在 sys.pycache_prefix
中报告(None
表示 __pycache__
子目录中的默认位置)。
(由 Carl Meyer 在 bpo-33499 中贡献。)
调试构建使用与发布构建相同的 ABI¶
现在,Python 无论是在发布模式还是调试模式下构建,都使用相同的 ABI。在 Unix 上,当 Python 以调试模式构建时,现在可以加载以发布模式构建的 C 扩展和使用稳定 ABI 构建的 C 扩展。
发布版本和调试版本现在是 ABI 兼容的:定义 Py_DEBUG
宏不再暗示 Py_TRACE_REFS
宏,这引入了唯一的 ABI 不兼容性。Py_TRACE_REFS
宏添加了 sys.getobjects()
函数和 PYTHONDUMPREFS
环境变量,可以使用新的 ./configure --with-trace-refs
构建选项设置。(由 Victor Stinner 在 bpo-36465 中贡献。)
在 Unix 上,C 扩展不再链接到 libpython,除非在 Android 和 Cygwin 上。现在,静态链接的 Python 可以加载使用共享库 Python 构建的 C 扩展。(由 Victor Stinner 在 bpo-21536 中贡献。)
在 Unix 上,当 Python 以调试模式构建时,导入现在还会查找以发布模式编译的 C 扩展和使用稳定 ABI 编译的 C 扩展。(由 Victor Stinner 在 bpo-36722 中贡献。)
要将 Python 嵌入到应用程序中,必须将新的 --embed
选项传递给 python3-config --libs --embed
,以获取 -lpython3.8
(将应用程序链接到 libpython)。为了同时支持 3.8 和更旧的版本,请先尝试 python3-config --libs --embed
,如果之前的命令失败,则回退到 python3-config --libs
(不带 --embed
)。
添加一个 pkg-config python-3.8-embed
模块,以便将 Python 嵌入到应用程序中:pkg-config python-3.8-embed --libs
包含 -lpython3.8
。为了同时支持 3.8 和更旧的版本,请先尝试 pkg-config python-X.Y-embed --libs
,如果之前的命令失败,则回退到 pkg-config python-X.Y --libs
(不带 --embed
)(将 X.Y
替换为 Python 版本)。
另一方面,pkg-config python3.8 --libs
不再包含 -lpython3.8
。C 扩展不应链接到 libpython(除非在 Android 和 Cygwin 上,这些情况由脚本处理);此更改是故意向后不兼容的。(由 Victor Stinner 在 bpo-36721 中贡献。)
f-字符串支持 =
,用于自文档化表达式和调试¶
向f-字符串添加了一个 =
说明符。诸如 f'{expr=}'
的 f-字符串将展开为表达式的文本、一个等号,然后是已评估表达式的表示。例如
>>> user = 'eric_idle'
>>> member_since = date(1975, 7, 31)
>>> f'{user=} {member_since=}'
"user='eric_idle' member_since=datetime.date(1975, 7, 31)"
通常的 f-字符串格式说明符 允许更好地控制表达式结果的显示方式
>>> delta = date.today() - member_since
>>> f'{user=!s} {delta.days=:,d}'
'user=eric_idle delta.days=16,075'
=
说明符将显示整个表达式,以便可以显示计算
>>> print(f'{theta=} {cos(radians(theta))=:.3f}')
theta=30 cos(radians(theta))=0.866
(由 Eric V. Smith 和 Larry Hastings 在 bpo-36817 中贡献。)
PEP 578:Python 运行时审计钩子¶
此 PEP 添加了审计钩子和验证开放钩子。两者都可从 Python 和本机代码中使用,允许用纯 Python 代码编写的应用程序和框架利用额外的通知,同时还允许嵌入程序或系统管理员部署始终启用审核的 Python 版本。
有关完整详细信息,请参阅 PEP 578。
PEP 587:Python 初始化配置¶
PEP 587 添加了一个新的 C API 来配置 Python 初始化,从而可以更好地控制整个配置并提供更好的错误报告。
新结构
新函数
此 PEP 还向这些内部结构添加了 _PyRuntimeState.preconfig
(PyPreConfig
类型)和 PyInterpreterState.config
(PyConfig
类型)字段。PyInterpreterState.config
将成为新的参考配置,取代全局配置变量和其他私有变量。
有关文档,请参阅 Python 初始化配置。
有关完整描述,请参阅 PEP 587。
(由 Victor Stinner 在 bpo-36763 中贡献。)
PEP 590:Vectorcall:CPython 的快速调用协议¶
Vectorcall 协议已添加到 Python/C API 中。它旨在形式化已经为各种类进行的现有优化。任何实现可调用接口的 静态类型都可以使用此协议。
这目前是临时的。目标是在 Python 3.9 中使其完全公开。
有关完整描述,请参阅 PEP 590。
(由 Jeroen Demeyer、Mark Shannon 和 Petr Viktorin 在 bpo-36974 中贡献。)
带有带外数据缓冲区的 Pickle 协议 5¶
当使用 pickle
在 Python 进程之间传输大量数据,以利用多核或多机处理时,通过减少内存复制来优化传输非常重要,并且可能通过应用诸如依赖于数据的压缩之类的自定义技术来优化传输。
pickle
协议 5 引入了对带外缓冲区的支持,其中 PEP 3118-兼容的数据可以与主 pickle 流分开传输,由通信层酌情决定。
有关完整描述,请参阅 PEP 574。
(由 Antoine Pitrou 在 bpo-36785 中贡献。)
其他语言变更¶
由于实现中的问题,
finally
子句中的continue
语句是非法的。在 Python 3.8 中,此限制被取消。(由 Serhiy Storchaka 在 bpo-32489 中贡献。)bool
、int
和fractions.Fraction
类型现在具有与float
和decimal.Decimal
中找到的类似的as_integer_ratio()
方法。此小的 API 扩展使得可以编写numerator, denominator = x.as_integer_ratio()
并且使其在多种数字类型中工作。(由 Lisa Roach 在 bpo-33073 和 Raymond Hettinger 在 bpo-37819 中贡献。)int
、float
和complex
的构造函数现在将使用__index__()
特殊方法(如果可用),并且当相应的__int__()
、__float__()
或__complex__()
方法不可用时。(由 Serhiy Storchaka 在 bpo-20092 中贡献。)在
正则表达式
中添加了对\N{name}
转义的支持。>>> notice = 'Copyright © 2019' >>> copyright_year_pattern = re.compile(r'\N{copyright sign}\s*(\d{4})') >>> int(copyright_year_pattern.search(notice).group(1)) 2019
(由 Jonathan Eunice 和 Serhiy Storchaka 在 bpo-30688 中贡献。)
现在可以使用
reversed()
以相反的插入顺序迭代字典和字典视图。(由 Rémi Lapeyre 在 bpo-33462 中贡献。)函数调用中关键字名称允许的语法受到了进一步的限制。特别是,不再允许
f((keyword)=arg)
。它从来都不打算允许在关键字参数赋值项的左侧使用裸名称。(由 Benjamin Peterson 在 bpo-34641 中贡献。)在
yield
和return
语句中,泛化的可迭代解包不再需要用圆括号括起来。这使得 *yield* 和 *return* 的语法与普通的赋值语法更加一致。>>> def parse(family): lastname, *members = family.split() return lastname.upper(), *members >>> parse('simpsons homer marge bart lisa maggie') ('SIMPSONS', 'homer', 'marge', 'bart', 'lisa', 'maggie')
(由 David Cuthbert 和 Jordan Chapman 在 bpo-32117 中贡献。)
当在诸如
[(10, 20) (30, 40)]
之类的代码中遗漏逗号时,编译器会显示SyntaxWarning
并提供有用的建议。这比仅仅使用指示第一个元组不可调用的TypeError
更好。(由 Serhiy Storchaka 在 bpo-15248 中贡献。)datetime.date
或datetime.datetime
的子类与datetime.timedelta
对象之间的算术运算现在返回子类的实例,而不是基类。这也会影响其实现(直接或间接地)使用datetime.timedelta
算术的运算的返回类型,例如astimezone()
。(由 Paul Ganssle 在 bpo-32417 中贡献。)当 Python 解释器被 Ctrl-C (SIGINT) 中断并且产生的
KeyboardInterrupt
异常未被捕获时,Python 进程现在将通过 SIGINT 信号或使用正确的退出代码退出,以便调用进程可以检测到它因 Ctrl-C 而终止。POSIX 和 Windows 上的 Shell 使用它来正确终止交互会话中的脚本。(由 Google 通过 Gregory P. Smith 在 bpo-1054041 中贡献。)一些高级编程风格需要更新现有函数的
types.CodeType
对象。由于代码对象是不可变的,因此需要创建一个新的代码对象,该对象以现有代码对象为模型。使用 19 个参数,这有点繁琐。现在,新的replace()
方法可以创建带有少量更改参数的克隆。这是一个示例,它更改了
statistics.mean()
函数,以防止 data 参数用作关键字参数>>> from statistics import mean >>> mean(data=[10, 20, 90]) 40 >>> mean.__code__ = mean.__code__.replace(co_posonlyargcount=1) >>> mean(data=[10, 20, 90]) Traceback (most recent call last): ... TypeError: mean() got some positional-only arguments passed as keyword arguments: 'data'
(由 Victor Stinner 在 bpo-37032 中贡献。)
对于整数,
pow()
函数的三参数形式现在允许当底数与模数互质时指数为负数。当指数为-1
时,它计算底数的模逆,对于其他负指数,计算该逆的适当幂。例如,要计算 38 模 137 的模乘逆,请写>>> pow(38, -1, 137) 119 >>> 119 * 38 % 137 1
模逆出现在线性丢番图方程的解中。例如,要找到
4258𝑥 + 147𝑦 = 369
的整数解,首先将其重写为4258𝑥 ≡ 369 (mod 147)
,然后求解>>> x = 369 * pow(4258, -1, 147) % 147 >>> y = (4258 * x - 369) // -147 >>> 4258 * x + 147 * y 369
(由 Mark Dickinson 在 bpo-36027 中贡献。)
字典推导式已与字典字面量同步,因此先计算键,然后再计算值。
>>> # Dict comprehension >>> cast = {input('role? '): input('actor? ') for i in range(2)} role? King Arthur actor? Chapman role? Black Knight actor? Cleese >>> # Dict literal >>> cast = {input('role? '): input('actor? ')} role? Sir Robin actor? Eric Idle
保证的执行顺序对于赋值表达式很有帮助,因为在键表达式中赋值的变量将在值表达式中可用。
>>> names = ['Martin von Löwis', 'Łukasz Langa', 'Walter Dörwald'] >>> {(n := normalize('NFC', name)).casefold() : n for name in names} {'martin von löwis': 'Martin von Löwis', 'łukasz langa': 'Łukasz Langa', 'walter dörwald': 'Walter Dörwald'}
(由 Jörn Heissler 在 bpo-35224 中贡献。)
object.__reduce__()
方法现在可以返回一个长度为 2 到 6 个元素的元组。以前,限制为 5 个。新的可选的第六个元素是具有(obj, state)
签名的可调用对象。这允许直接控制特定对象的状态更新行为。如果不是 None,则此可调用对象将优先于对象的__setstate__()
方法。(由 Pierre Glaser 和 Olivier Grisel 在 bpo-35900 中贡献。)
新模块¶
新的
importlib.metadata
模块为读取第三方包的元数据提供了(临时的)支持。例如,它可以提取已安装包的版本号、入口点列表等。>>> # Note following example requires that the popular "requests" >>> # package has been installed. >>> >>> from importlib.metadata import version, requires, files >>> version('requests') '2.22.0' >>> list(requires('requests')) ['chardet (<3.1.0,>=3.0.2)'] >>> list(files('requests'))[:5] [PackagePath('requests-2.22.0.dist-info/INSTALLER'), PackagePath('requests-2.22.0.dist-info/LICENSE'), PackagePath('requests-2.22.0.dist-info/METADATA'), PackagePath('requests-2.22.0.dist-info/RECORD'), PackagePath('requests-2.22.0.dist-info/WHEEL')]
(由 Barry Warsaw 和 Jason R. Coombs 在 bpo-34632 中贡献。)
改进的模块¶
ast¶
AST 节点现在具有 end_lineno
和 end_col_offset
属性,这些属性给出了节点末端的精确位置。(这仅适用于具有 lineno
和 col_offset
属性的节点。)
新函数 ast.get_source_segment()
返回特定 AST 节点的源代码。
(由 Ivan Levkivskyi 在 bpo-33416 中贡献。)
ast.parse()
函数有一些新的标志。
type_comments=True
会使其返回与某些 AST 节点关联的 PEP 484 和 PEP 526 类型注释的文本;mode='func_type'
可用于解析 PEP 484 “签名类型注释”(为函数定义 AST 节点返回);feature_version=(3, N)
允许指定更早的 Python 3 版本。例如,feature_version=(3, 4)
会将async
和await
视为非保留字。
(由 Guido van Rossum 在 bpo-35766 中贡献。)
asyncio¶
asyncio.run()
已从临时 API 升级为稳定 API。此函数可用于执行 协程 并返回结果,同时自动管理事件循环。例如
import asyncio
async def main():
await asyncio.sleep(0)
return 42
asyncio.run(main())
这大致等同于
import asyncio
async def main():
await asyncio.sleep(0)
return 42
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
loop.run_until_complete(main())
finally:
asyncio.set_event_loop(None)
loop.close()
实际实现要复杂得多。因此,asyncio.run()
应该是运行 asyncio 程序的首选方式。
(由 Yury Selivanov 在 bpo-32314 中贡献。)
运行 python -m asyncio
会启动一个原生异步 REPL。这允许快速尝试具有顶级 await
的代码。不再需要直接调用 asyncio.run()
,这会在每次调用时生成一个新的事件循环
$ python -m asyncio
asyncio REPL 3.8.0
Use "await" directly instead of "asyncio.run()".
Type "help", "copyright", "credits" or "license" for more information.
>>> import asyncio
>>> await asyncio.sleep(10, result='hello')
hello
(由 Yury Selivanov 在 bpo-37028 中贡献。)
异常 asyncio.CancelledError
现在继承自 BaseException
而不是 Exception
,并且不再继承自 concurrent.futures.CancelledError
。(由 Yury Selivanov 在 bpo-32528 中贡献。)
在 Windows 上,默认事件循环现在是 ProactorEventLoop
。(由 Victor Stinner 在 bpo-34687 中贡献。)
ProactorEventLoop
现在还支持 UDP。(由 Adam Meily 和 Andrew Svetlov 在 bpo-29883 中贡献。)
ProactorEventLoop
现在可以通过 KeyboardInterrupt
(“CTRL+C”) 中断。(由 Vladimir Matveev 在 bpo-23057 中贡献。)
添加了 asyncio.Task.get_coro()
用于获取 asyncio.Task
内包装的协程。(由 Alex Grönholm 在 bpo-36999 中贡献。)
Asyncio 任务现在可以通过将 name
关键字参数传递给 asyncio.create_task()
或 create_task()
事件循环方法,或者通过在任务对象上调用 set_name()
方法来命名。任务名称在 asyncio.Task
的 repr()
输出中可见,也可以使用 get_name()
方法检索。(由 Alex Grönholm 在 bpo-34270 中贡献。)
为 asyncio.loop.create_connection()
添加了对 Happy Eyeballs 的支持。为了指定行为,添加了两个新参数:happy_eyeballs_delay 和 interleave。Happy Eyeballs 算法通过尝试同时使用 IPv4 和 IPv6 连接来提高支持 IPv4 和 IPv6 的应用程序的响应能力。(由 twisteroid ambassador 在 bpo-33530 中贡献。)
builtins¶
compile()
内置函数已得到改进,可以接受 ast.PyCF_ALLOW_TOP_LEVEL_AWAIT
标志。通过传递这个新标志,compile()
将允许通常被认为是无效语法的顶级 await
、async for
和 async with
构造。然后可能会返回标记有 CO_COROUTINE
标志的异步代码对象。(由 Matthias Bussonnier 在 bpo-34616 中贡献)
collections¶
_asdict()
方法用于 collections.namedtuple()
现在返回 dict
而不是 collections.OrderedDict
。这是可行的,因为自 Python 3.7 以来,常规 dict 保证了排序。如果需要 OrderedDict
的额外功能,建议的补救方法是将结果强制转换为所需的类型:OrderedDict(nt._asdict())
。(由 Raymond Hettinger 在 bpo-35864 中贡献。)
cProfile¶
cProfile.Profile
类现在可以用作上下文管理器。通过运行以下代码来分析代码块
import cProfile
with cProfile.Profile() as profiler:
# code to be profiled
...
(由 Scott Sanderson 在 bpo-29235 中贡献。)
csv¶
csv.DictReader
现在返回 dict
的实例,而不是 collections.OrderedDict
。该工具现在更快,使用更少的内存,同时仍然保留字段顺序。(由 Michael Selik 在 bpo-34003 中贡献。)
curses¶
为底层 ncurses 库添加了一个新的变量,用于保存结构化的版本信息:ncurses_version
。(由 Serhiy Storchaka 在 bpo-31680 中贡献。)
ctypes¶
在 Windows 上,CDLL
及其子类现在接受一个 winmode 参数,用于为底层的 LoadLibraryEx
调用指定标志。默认标志设置为仅从可信位置加载 DLL 依赖项,包括 DLL 存储的路径(如果使用完整或部分路径加载初始 DLL)以及通过 add_dll_directory()
添加的路径。(由 Steve Dower 在 bpo-36085 中贡献。)
datetime¶
添加了新的替代构造函数 datetime.date.fromisocalendar()
和 datetime.datetime.fromisocalendar()
,它们分别从 ISO 年、周数和星期几构造 date
和 datetime
对象;这些是每个类的 isocalendar
方法的逆操作。(由 Paul Ganssle 在 bpo-36004 中贡献。)
functools¶
functools.lru_cache()
现在可以用作直接装饰器,而不是返回装饰器的函数。因此,现在支持以下两种方式:
@lru_cache
def f(x):
...
@lru_cache(maxsize=256)
def f(x):
...
(由 Raymond Hettinger 在 bpo-36772 中贡献。)
添加了一个新的 functools.cached_property()
装饰器,用于缓存实例生命周期内的计算属性。
import functools
import statistics
class Dataset:
def __init__(self, sequence_of_numbers):
self.data = sequence_of_numbers
@functools.cached_property
def variance(self):
return statistics.variance(self.data)
(由 Carl Meyer 在 bpo-21145 中贡献)
添加了一个新的 functools.singledispatchmethod()
装饰器,它使用 单分派 将方法转换为 泛型函数
from functools import singledispatchmethod
from contextlib import suppress
class TaskManager:
def __init__(self, tasks):
self.tasks = list(tasks)
@singledispatchmethod
def discard(self, value):
with suppress(ValueError):
self.tasks.remove(value)
@discard.register(list)
def _(self, tasks):
targets = set(tasks)
self.tasks = [x for x in self.tasks if x not in targets]
(由 Ethan Smith 在 bpo-32380 中贡献)
gc¶
get_objects()
现在可以接收一个可选的 generation 参数,指示要从中获取对象的代数。(由 Pablo Galindo 在 bpo-36016 中贡献。)
gettext¶
添加了 pgettext()
及其变体。(由 Franz Glasner、Éric Araujo 和 Cheryl Sabella 在 bpo-2504 中贡献。)
gzip¶
为 gzip.compress()
添加了 mtime 参数,以实现可重现的输出。(由 Guo Ci Teo 在 bpo-34898 中贡献。)
现在,对于某些类型的无效或损坏的 gzip 文件,会引发 BadGzipFile
异常,而不是 OSError
。(由 Filip Gruszczyński、Michele Orrù 和 Zackery Spytz 在 bpo-6584 中贡献。)
IDLE 和 idlelib¶
超过 N 行(默认为 50)的输出将被压缩成一个按钮。N 可以在“设置”对话框的“常规”页面的“PyShell”部分中更改。可以通过右键单击输出来压缩较少但可能非常长的行。可以通过双击按钮来就地展开压缩的输出,或者通过右键单击按钮将其展开到剪贴板或单独的窗口中。(由 Tal Einat 在 bpo-1529353 中贡献。)
将“运行自定义”添加到“运行”菜单,以使用自定义设置运行模块。输入的任何命令行参数都将添加到 sys.argv 中。它们也会在下次自定义运行时重新出现在框中。还可以禁止正常的 Shell 主模块重启。(由 Cheryl Sabella、Terry Jan Reedy 和其他人在 bpo-5680 和 bpo-37627 中贡献。)
为 IDLE 编辑器窗口添加了可选的行号。默认情况下,窗口在不显示行号的情况下打开,除非在配置对话框的“常规”选项卡中另行设置。现有窗口的行号在“选项”菜单中显示和隐藏。(由 Tal Einat 和 Saimadhav Heblikar 在 bpo-17535 中贡献。)
现在使用操作系统本机编码在 Python 字符串和 Tcl 对象之间进行转换。这允许 IDLE 使用 emoji 和其他非 BMP 字符。这些字符可以显示或复制并粘贴到剪贴板或从剪贴板复制并粘贴。现在,将字符串从 Tcl 转换为 Python 并返回时永远不会失败。(许多人为此工作了八年,但这个问题最终由 Serhiy Storchaka 在 bpo-13153 中解决。)
3.8.1 中的新增功能
添加了关闭光标闪烁的选项。(由 Zackery Spytz 在 bpo-4603 中贡献。)
现在,按 Escape 键会关闭 IDLE 完成窗口。(由 Johnny Najera 在 bpo-38944 中贡献。)
以上更改已向后移植到 3.7 维护版本。
将关键字添加到模块名称完成列表中。(由 Terry J. Reedy 在 bpo-37765 中贡献。)
inspect¶
如果 __slots__
属性是值是文档字符串的 dict
,则 inspect.getdoc()
函数现在可以查找 __slots__
的文档字符串。这提供了类似于我们已经为 property()
、classmethod()
和 staticmethod()
提供的文档选项
class AudioClip:
__slots__ = {'bit_rate': 'expressed in kilohertz to one decimal place',
'duration': 'in seconds, rounded up to an integer'}
def __init__(self, bit_rate, duration):
self.bit_rate = round(bit_rate / 1000.0, 1)
self.duration = ceil(duration)
(由 Raymond Hettinger 在 bpo-36326 中贡献。)
io¶
在开发模式 (-X
env
) 和在 调试构建 中,如果 close()
方法失败,io.IOBase
终结器现在会记录异常。默认情况下,在发布版本中,异常会被静默忽略。(由 Victor Stinner 在 bpo-18748 中贡献。)
itertools¶
itertools.accumulate()
函数添加了一个可选的 initial 关键字参数来指定初始值
>>> from itertools import accumulate
>>> list(accumulate([10, 5, 30, 15], initial=1000))
[1000, 1010, 1015, 1045, 1060]
(由 Lisa Roach 在 bpo-34659 中贡献。)
json.tool¶
添加选项 --json-lines
以将每个输入行解析为单独的 JSON 对象。(由 Weipeng Hong 在 bpo-31553 中贡献。)
logging¶
为 logging.basicConfig()
添加了一个 force 关键字参数。当设置为 true 时,在执行其他参数指定的配置之前,将删除并关闭附加到根记录器的任何现有处理程序。
这解决了一个长期存在的问题。一旦调用了记录器或 basicConfig(),后续对 basicConfig() 的调用将被静默忽略。这使得使用交互式提示符或 Jupyter 笔记本更新、试验或教授各种日志记录配置选项变得很困难。
(由 Raymond Hettinger 建议,Donghee Na 实现,Vinay Sajip 在 bpo-33897 中审阅。)
math¶
添加了新函数 math.dist()
,用于计算两点之间的欧几里得距离。(由 Raymond Hettinger 在 bpo-33089 中贡献。)
扩展了 math.hypot()
函数以处理多个维度。以前,它只支持 2-D 情况。(由 Raymond Hettinger 在 bpo-33089 中贡献。)
添加了新函数 math.prod()
,作为 sum()
的类似函数,它返回一个 ‘start’ 值(默认为 1)乘以一个数字可迭代对象的结果
>>> prior = 0.8
>>> likelihoods = [0.625, 0.84, 0.30]
>>> math.prod(likelihoods, start=prior)
0.126
(由 Pablo Galindo 在 bpo-35606 中贡献。)
增加了两个新的组合数学函数 math.perm()
和 math.comb()
>>> math.perm(10, 3) # Permutations of 10 things taken 3 at a time
720
>>> math.comb(10, 3) # Combinations of 10 things taken 3 at a time
120
(由 Yash Aggarwal、Keller Fuchs、Serhiy Storchaka 和 Raymond Hettinger 在 bpo-37128、bpo-37178 和 bpo-35431 中贡献。)
增加了一个新函数 math.isqrt()
,用于计算精确的整数平方根,而无需转换为浮点数。新函数支持任意大的整数。它比 floor(sqrt(n))
快,但比 math.sqrt()
慢。
>>> r = 650320427
>>> s = r ** 2
>>> isqrt(s - 1) # correct
650320426
>>> floor(sqrt(s - 1)) # incorrect
650320427
(由 Mark Dickinson 在 bpo-36887 中贡献。)
函数 math.factorial()
不再接受非 int-like 的参数。(由 Pablo Galindo 在 bpo-33083 中贡献。)
mmap¶
mmap.mmap
类现在有一个 madvise()
方法来访问 madvise()
系统调用。(由 Zackery Spytz 在 bpo-32941 中贡献。)
multiprocessing¶
添加了新的 multiprocessing.shared_memory
模块。(由 Davin Potts 在 bpo-35813 中贡献。)
在 macOS 上,默认使用 spawn 启动方法。(由 Victor Stinner 在 bpo-33725 中贡献。)
os¶
在 Windows 上添加了新函数 add_dll_directory()
,用于在导入扩展模块或使用 ctypes
加载 DLL 时提供额外的本机依赖项搜索路径。(由 Steve Dower 在 bpo-36085 中贡献。)
添加了一个新的 os.memfd_create()
函数来包装 memfd_create()
系统调用。(由 Zackery Spytz 和 Christian Heimes 在 bpo-26836 中贡献。)
在 Windows 上,处理重分析点(包括符号链接和目录连接)的大部分手动逻辑已委托给操作系统。具体来说,os.stat()
现在将遍历操作系统支持的任何内容,而 os.lstat()
将仅打开标识为“名称代理”的重分析点,而其他重分析点将像 os.stat()
一样打开。在所有情况下,stat_result.st_mode
仅对符号链接设置 S_IFLNK
,而不对其他类型的重分析点设置。要识别其他类型的重分析点,请检查新的 stat_result.st_reparse_tag
属性。
在 Windows 上,os.readlink()
现在能够读取目录连接。请注意,islink()
对于目录连接将返回 False
,因此首先检查 islink
的代码将继续将连接视为目录,而处理来自 os.readlink()
的错误的代码现在可能会将连接视为链接。
(由 Steve Dower 在 bpo-37834 中贡献。)
os.path¶
返回布尔结果的 os.path
函数,如 exists()
、lexists()
、isdir()
、isfile()
、islink()
和 ismount()
,现在对于包含在操作系统级别无法表示的字符或字节的路径,将返回 False
,而不是引发 ValueError
或其子类 UnicodeEncodeError
和 UnicodeDecodeError
。(由 Serhiy Storchaka 在 bpo-33721 中贡献。)
Windows 上的 expanduser()
现在更倾向于使用 USERPROFILE
环境变量,而不是使用 HOME
,后者通常不为常规用户帐户设置。(由 Anthony Sottile 在 bpo-36264 中贡献。)
Windows 上的 isdir()
不再为指向不存在的目录的链接返回 True
。
Windows 上的 realpath()
现在会解析重分析点,包括符号链接和目录连接。
(由 Steve Dower 在 bpo-37834 中贡献。)
pathlib¶
返回布尔结果的 pathlib.Path
方法,如 exists()
、is_dir()
、is_file()
、is_mount()
、is_symlink()
、is_block_device()
、is_char_device()
、is_fifo()
、is_socket()
,现在对于包含在操作系统级别无法表示的字符的路径,将返回 False
,而不是引发 ValueError
或其子类 UnicodeEncodeError
。(由 Serhiy Storchaka 在 bpo-33721 中贡献。)
添加了 pathlib.Path.link_to()
,用于创建一个指向路径的硬链接。(由 Joannah Nanjekye 在 bpo-26978 中贡献) 请注意,link_to
在 3.10 中被弃用,并在 3.12 中被删除,取而代之的是在 3.10 中添加的 hardlink_to
方法,该方法匹配现有 symlink_to
方法的语义。
pickle¶
继承自 C 优化的 Pickler
的 pickle
扩展现在可以通过定义特殊的 reducer_override()
方法来覆盖函数和类的 pickling 逻辑。(由 Pierre Glaser 和 Olivier Grisel 在 bpo-35900 中贡献。)
plistlib¶
添加了新的 plistlib.UID
,并支持读取和写入 NSKeyedArchiver 编码的二进制 plist。(由 Jon Janzen 在 bpo-26707 中贡献。)
pprint¶
pprint
模块为多个函数添加了 sort_dicts 参数。默认情况下,这些函数在渲染或打印之前继续对字典进行排序。但是,如果将 sort_dicts 设置为 false,则字典会保留键插入的顺序。这在调试期间与 JSON 输入进行比较时很有用。
此外,还有一个方便的新函数 pprint.pp()
,它类似于 pprint.pprint()
,但 sort_dicts 默认值为 False
。
>>> from pprint import pprint, pp
>>> d = dict(source='input.txt', operation='filter', destination='output.txt')
>>> pp(d, width=40) # Original order
{'source': 'input.txt',
'operation': 'filter',
'destination': 'output.txt'}
>>> pprint(d, width=40) # Keys sorted alphabetically
{'destination': 'output.txt',
'operation': 'filter',
'source': 'input.txt'}
(由 Rémi Lapeyre 在 bpo-30670 中贡献。)
py_compile¶
py_compile.compile()
现在支持静默模式。(由 Joannah Nanjekye 在 bpo-22640 中贡献。)
shlex¶
新的 shlex.join()
函数充当 shlex.split()
的反向操作。(由 Bo Bayles 在 bpo-32102 中贡献。)
shutil¶
shutil.copytree()
现在接受一个新的 dirs_exist_ok
关键字参数。(由 Josh Bronson 在 bpo-20849 中贡献。)
shutil.make_archive()
现在默认为新的存档使用现代 pax (POSIX.1-2001) 格式,以提高可移植性和标准一致性,这继承自对 tarfile
模块的相应更改。(由 C.A.M. Gerlach 在 bpo-30661 中贡献。)
Windows 上的 shutil.rmtree()
现在删除目录连接,而不会首先递归删除其内容。(由 Steve Dower 在 bpo-37834 中贡献。)
socket¶
添加了 create_server()
和 has_dualstack_ipv6()
便利函数,以自动化创建服务器套接字时通常涉及的必要任务,包括在同一套接字上接受 IPv4 和 IPv6 连接。(由 Giampaolo Rodolà 在 bpo-17561 中贡献。)
socket.if_nameindex()
、socket.if_nametoindex()
和 socket.if_indextoname()
函数已在 Windows 上实现。(由 Zackery Spytz 在 bpo-37007 中贡献。)
ssl¶
添加了 post_handshake_auth
以启用和 verify_client_post_handshake()
来启动 TLS 1.3 后握手身份验证。(由 Christian Heimes 在 bpo-34670 中贡献。)
statistics¶
添加了 statistics.fmean()
,它是 statistics.mean()
的更快、浮点变体。(由 Raymond Hettinger 和 Steven D’Aprano 在 bpo-35904 中贡献。)
添加了 statistics.geometric_mean()
(由 Raymond Hettinger 在 bpo-27181 中贡献。)
添加了 statistics.multimode()
,它返回最常见值的列表。(由 Raymond Hettinger 在 bpo-35892 中贡献。)
添加了 statistics.quantiles()
,它将数据或分布划分为等概率区间(例如,四分位数、十分位数或百分位数)。(由 Raymond Hettinger 在 bpo-36546 中贡献。)
添加了 statistics.NormalDist
,这是一个用于创建和操作随机变量正态分布的工具。(由 Raymond Hettinger 在 bpo-36018 中贡献。)
>>> temperature_feb = NormalDist.from_samples([4, 12, -3, 2, 7, 14])
>>> temperature_feb.mean
6.0
>>> temperature_feb.stdev
6.356099432828281
>>> temperature_feb.cdf(3) # Chance of being under 3 degrees
0.3184678262814532
>>> # Relative chance of being 7 degrees versus 10 degrees
>>> temperature_feb.pdf(7) / temperature_feb.pdf(10)
1.2039930378537762
>>> el_niño = NormalDist(4, 2.5)
>>> temperature_feb += el_niño # Add in a climate effect
>>> temperature_feb
NormalDist(mu=10.0, sigma=6.830080526611674)
>>> temperature_feb * (9/5) + 32 # Convert to Fahrenheit
NormalDist(mu=50.0, sigma=12.294144947901014)
>>> temperature_feb.samples(3) # Generate random samples
[7.672102882379219, 12.000027119750287, 4.647488369766392]
sys¶
添加新的 sys.unraisablehook()
函数,可以重写以控制如何处理“无法引发的异常”。当发生异常但 Python 无法处理时,会调用此函数。例如,当析构函数引发异常或在垃圾回收期间 (gc.collect()
)。(由 Victor Stinner 在 bpo-36829 中贡献。)
tarfile¶
tarfile
模块现在默认为新的存档使用现代 pax (POSIX.1-2001) 格式,而不是以前的 GNU 特定格式。这通过在标准且可扩展的格式中使用一致的编码 (UTF-8) 提高了跨平台的可移植性,并提供了其他一些好处。(由 C.A.M. Gerlach 在 bpo-36268 中贡献。)
threading¶
添加一个新的 threading.excepthook()
函数,用于处理未捕获的 threading.Thread.run()
异常。可以重写它以控制如何处理未捕获的 threading.Thread.run()
异常。(由 Victor Stinner 在 bpo-1230540 中贡献。)
为 threading.Thread
类添加了一个新的 threading.get_native_id()
函数和一个 native_id
属性。这些返回内核分配的当前线程的本机整数线程 ID。此功能仅在某些平台上可用,有关详细信息,请参阅 get_native_id
。(由 Jake Tesler 在 bpo-36084 中贡献。)
tokenize¶
当提供的输入不以换行符结尾时,tokenize
模块现在会隐式地发出一个 NEWLINE
令牌。此行为现在与 C 词法分析器在内部执行的操作相匹配。(由 Ammar Askar 在 bpo-33899 中贡献。)
tkinter¶
在 tkinter.Spinbox
类中添加了方法 selection_from()
,selection_present()
,selection_range()
和 selection_to()
。(由 Juliette Monsel 在 bpo-34829 中贡献。)
在 tkinter.Canvas
类中添加了方法 moveto()
。(由 Juliette Monsel 在 bpo-23831 中贡献。)
tkinter.PhotoImage
类现在具有 transparency_get()
和 transparency_set()
方法。(由 Zackery Spytz 在 bpo-25451 中贡献。)
time¶
为 macOS 10.12 添加了新的时钟 CLOCK_UPTIME_RAW
。(由 Joannah Nanjekye 在 bpo-35702 中贡献。)
typing¶
typing
模块包含多个新功能
具有每个键类型的字典类型。 请参阅 PEP 589 和
typing.TypedDict
。 TypedDict 仅使用字符串键。默认情况下,每个键都必须存在。 指定“total=False”以允许键是可选的class Location(TypedDict, total=False): lat_long: tuple grid_square: str xy_coordinate: tuple
字面类型。请参阅 PEP 586 和
typing.Literal
。字面类型表示参数或返回值被限制为一个或多个特定的字面值def get_status(port: int) -> Literal['connected', 'disconnected']: ...
“Final” 变量、函数、方法和类。请参阅 PEP 591,
typing.Final
和typing.final()
。final 限定符指示静态类型检查器限制子类化、覆盖或重新赋值pi: Final[float] = 3.1415926536
协议定义。请参阅 PEP 544,
typing.Protocol
和typing.runtime_checkable()
。诸如typing.SupportsInt
之类的简单 ABC 现在是Protocol
子类。新的协议类
typing.SupportsIndex
。
unicodedata¶
unicodedata
模块已升级为使用 Unicode 12.1.0 版本。
新函数 is_normalized()
可用于验证字符串是否为特定的标准形式,这通常比实际标准化字符串快得多。(由 Max Belanger、David Euresti 和 Greg Price 在 bpo-32285 和 bpo-37966 中贡献。)
unittest¶
添加了 AsyncMock
以支持 Mock
的异步版本。 还添加了适当的新断言函数用于测试。(由 Lisa Roach 在 bpo-26467 中贡献。)
为 unittest 添加了 addModuleCleanup()
和 addClassCleanup()
,以支持 setUpModule()
和 setUpClass()
的清理。(由 Lisa Roach 在 bpo-24412 中贡献。)
几个 mock 断言函数现在在失败时还会打印实际调用的列表。(由 Petter Strandmark 在 bpo-35047 中贡献。)
unittest
模块增加了对使用 unittest.IsolatedAsyncioTestCase
作为测试用例的协程的支持。(由 Andrew Svetlov 在 bpo-32972 中贡献。)
示例
import unittest
class TestRequest(unittest.IsolatedAsyncioTestCase):
async def asyncSetUp(self):
self.connection = await AsyncConnection()
async def test_get(self):
response = await self.connection.get("https://example.com")
self.assertEqual(response.status_code, 200)
async def asyncTearDown(self):
await self.connection.close()
if __name__ == "__main__":
unittest.main()
venv¶
venv
现在在所有平台上都包含一个 Activate.ps1
脚本,用于在 PowerShell Core 6.1 下激活虚拟环境。(由 Brett Cannon 在 bpo-32718 中贡献。)
weakref¶
weakref.proxy()
返回的代理对象现在除了其他数字运算符外,还支持矩阵乘法运算符 @
和 @=
。(由 Mark Dickinson 在 bpo-36669 中贡献。)
xml¶
作为对 DTD 和外部实体检索的缓解措施,xml.dom.minidom
和 xml.sax
模块默认不再处理外部实体。(由 Christian Heimes 在 bpo-17239 中贡献。)
xml.etree.ElementTree
模块中的 .find*()
方法支持通配符搜索,如 {*}tag
,它忽略命名空间,以及 {namespace}*
,它返回给定命名空间中的所有标签。(由 Stefan Behnel 在 bpo-28238 中贡献。)
xml.etree.ElementTree
模块提供了一个新函数 –xml.etree.ElementTree.canonicalize()
,它实现了 C14N 2.0。(由 Stefan Behnel 在 bpo-13611 中贡献。)
xml.etree.ElementTree.XMLParser
的目标对象可以通过新的回调方法 start_ns()
和 end_ns()
接收命名空间声明事件。此外,可以将 xml.etree.ElementTree.TreeBuilder
目标配置为处理关于注释和处理指令的事件,以将其包含在生成的树中。(由 Stefan Behnel 在 bpo-36676 和 bpo-36673 中贡献。)
xmlrpc¶
xmlrpc.client.ServerProxy
现在支持一个可选的 headers 关键字参数,用于指定随每个请求发送的 HTTP 标头序列。 除此之外,这使得从默认的基本身份验证升级到更快的会话身份验证成为可能。(由 Cédric Krier 在 bpo-35153 中贡献。)
优化¶
subprocess
模块现在可以在某些情况下使用os.posix_spawn()
函数以获得更好的性能。目前,仅当满足以下所有条件时,它才在 macOS 和 Linux(使用 glibc 2.24 或更高版本)上使用close_fds 为 false;
未设置 preexec_fn、pass_fds、cwd 和 start_new_session 参数;
executable 路径包含目录。
(由 Joannah Nanjekye 和 Victor Stinner 在 bpo-35537 中贡献。)
shutil.copyfile()
,shutil.copy()
,shutil.copy2()
,shutil.copytree()
和shutil.move()
在 Linux 和 macOS 上使用特定于平台的“快速复制”系统调用,以便更有效地复制文件。“快速复制”意味着复制操作发生在内核中,避免了像 “outfd.write(infd.read())
” 那样在 Python 中使用用户空间缓冲区。在 Windows 上,shutil.copyfile()
使用更大的默认缓冲区大小(1 MiB 而不是 16 KiB)和一个基于memoryview()
的shutil.copyfileobj()
变体。在同一分区内复制 512 MiB 文件时,速度在 Linux 上提高约 +26%,在 macOS 上提高约 +50%,在 Windows 上提高约 +40%。此外,消耗的 CPU 周期也少得多。请参阅 平台相关的有效复制操作 部分。(由 Giampaolo Rodolà 在 bpo-33671 中贡献。)shutil.copytree()
使用os.scandir()
函数,并且所有依赖于它的复制函数都使用缓存的os.stat()
值。复制包含 8000 个文件的目录的速度在 Linux 上提高了约 +9%,在 Windows 上提高了约 +20%,在 Windows SMB 共享上提高了约 +30%。此外,os.stat()
系统调用的数量减少了 38%,这使得shutil.copytree()
在网络文件系统上尤其更快。(由 Giampaolo Rodolà 在 bpo-33695 中贡献。)pickle
模块中的默认协议现在是 Protocol 4,它最早在 Python 3.4 中引入。 与自 Python 3.0 起可用的 Protocol 3 相比,它提供了更好的性能和更小的尺寸。从
PyGC_Head
中删除了一个Py_ssize_t
成员。 所有 GC 跟踪的对象(例如元组、列表、字典)的大小都减少了 4 或 8 个字节。(由 Inada Naoki 在 bpo-33597 中贡献。)uuid.UUID
现在使用__slots__
来减少其内存占用。(由 Wouter Bolsterlee 和 Tal Einat 在 bpo-30977 中贡献)将
operator.itemgetter()
的性能提高了 33%。优化了参数处理,并为元组中单个非负整数索引的常见情况(这是标准库中的典型用例)添加了快速路径。(由 Raymond Hettinger 在 bpo-35664 中贡献。)加快了
collections.namedtuple()
中的字段查找。它们现在快了两倍以上,使其成为 Python 中最快的实例变量查找形式。(由 Raymond Hettinger、Pablo Galindo 和 Joe Jevnik、Serhiy Storchaka 在 bpo-32492 中贡献。)如果输入的可迭代对象具有已知的长度(输入实现了
__len__
),则list
构造函数不会过度分配内部项目缓冲区。这使得创建的列表平均小 12%。(由 Raymond Hettinger 和 Pablo Galindo 在 bpo-33234 中贡献。)类变量写入的速度提高了一倍。当更新非双下划线属性时,会不必要地调用更新槽。(由 Stefan Behnel、Pablo Galindo Salgado、Raymond Hettinger、Neil Schemenauer 和 Serhiy Storchaka 在 bpo-36012 中贡献。)
减少了将参数传递给许多内置函数和方法的开销。 这将某些简单的内置函数和方法的调用速度提高了 20-50%。(由 Serhiy Storchaka 在 bpo-23867, bpo-35582 和 bpo-36127 中贡献。)
LOAD_GLOBAL
指令现在使用新的“每个操作码缓存”机制。 它现在快了大约 40%。(由 Yury Selivanov 和 Inada Naoki 在 bpo-26219 中贡献。)
构建和 C API 更改¶
默认的
sys.abiflags
变成了一个空字符串:pymalloc 的m
标志变得无用(有和没有 pymalloc 的构建是 ABI 兼容的),因此已被删除。(由 Victor Stinner 在 bpo-36707 中贡献。)更改示例
仅安装
python3.8
程序,python3.8m
程序已消失。仅安装
python3.8-config
脚本,python3.8m-config
脚本已消失。已从动态库文件名的后缀中删除了
m
标志:标准库中的扩展模块以及第三方软件包生成和安装的扩展模块,例如从 PyPI 下载的扩展模块。 例如,在 Linux 上,Python 3.7 后缀.cpython-37m-x86_64-linux-gnu.so
在 Python 3.8 中变为.cpython-38-x86_64-linux-gnu.so
。
已重新组织头文件,以更好地分离不同类型的 API
Include/*.h
应该是可移植的公共稳定 C API。Include/cpython/*.h
应该是特定于 CPython 的不稳定 C API;公共 API,其中一些私有 API 的前缀为_Py
或_PY
。Include/internal/*.h
是 CPython 特有的私有内部 C API。 此 API 没有向后兼容性保证,不应在 CPython 外部使用。 它仅用于非常特定的需求,例如必须访问 CPython 内部而无需调用函数的调试器和配置文件。 此 API 现在由make install
安装。
(由 Victor Stinner 在 bpo-35134 和 bpo-35081 中贡献,Eric Snow 在 Python 3.7 中启动的工作。)
一些宏已转换为静态内联函数:参数类型和返回类型已明确定义,它们没有特定于宏的问题,变量具有局部作用域。 示例
PyObject_INIT()
,PyObject_INIT_VAR()
私有函数:
_PyObject_GC_TRACK()
,_PyObject_GC_UNTRACK()
,_Py_Dealloc()
(由 Victor Stinner 在 bpo-35059 中贡献。)
PyByteArray_Init()
和PyByteArray_Fini()
函数已被移除。自从 Python 2.7.4 和 Python 3.2.0 以来,它们就没有任何作用,并且被排除在有限 API(稳定 ABI)之外,也没有被文档化。(由 Victor Stinner 在 bpo-35713 中贡献。)PyExceptionClass_Name()
的结果现在是const char *
类型,而不是char *
。(由 Serhiy Storchaka 在 bpo-33818 中贡献。)Modules/Setup.dist
和Modules/Setup
的双重性已被移除。之前,当更新 CPython 源代码树时,为了反映上游的任何更改,必须手动将Modules/Setup.dist
(在源代码树内)复制到Modules/Setup
(在构建树内)。这对打包者来说只是一个小小的便利,但对于跟踪 CPython 开发的开发者来说却是一个频繁的烦恼,因为忘记复制该文件可能会导致构建失败。现在,构建系统总是从源代码树内的
Modules/Setup
读取。鼓励想要自定义该文件的人将他们的更改维护在 CPython 的 git 分支中,或者作为补丁文件,就像他们对源代码树的任何其他更改所做的那样。(由 Antoine Pitrou 在 bpo-32430 中贡献。)
将 Python 数字转换为 C 整数的函数,如
PyLong_AsLong()
,以及带有整数转换格式单元(如'i'
)的参数解析函数,如PyArg_ParseTuple()
,现在将使用__index__()
特殊方法(如果可用),而不是__int__()
。对于具有__int__()
方法但没有__index__()
方法的对象(如Decimal
和Fraction
),将发出弃用警告。PyNumber_Check()
现在将为实现__index__()
的对象返回1
。PyNumber_Long()
、PyNumber_Float()
和PyFloat_AsDouble()
现在也会在可用时使用__index__()
方法。(由 Serhiy Storchaka 在 bpo-36048 和 bpo-20092 中贡献。)堆分配的类型对象现在将在
PyObject_Init()
(及其并行宏PyObject_INIT
)中增加它们的引用计数,而不是在PyType_GenericAlloc()
中。修改实例分配或释放的类型可能需要进行调整。(由 Eddie Elizondo 在 bpo-35810 中贡献。)新的函数
PyCode_NewWithPosOnlyArgs()
允许创建代码对象,类似于PyCode_New()
,但带有一个额外的 posonlyargcount 参数,用于指示仅位置参数的数量。(由 Pablo Galindo 在 bpo-37221 中贡献。)Py_SetPath()
现在将sys.executable
设置为程序的完整路径 (Py_GetProgramFullPath()
),而不是程序名称 (Py_GetProgramName()
)。(由 Victor Stinner 在 bpo-38234 中贡献。)
已弃用¶
distutils 的
bdist_wininst
命令现在已弃用,请改用bdist_wheel
(wheel 包)。(由 Victor Stinner 在 bpo-37481 中贡献。)ElementTree
模块中已弃用的方法getchildren()
和getiterator()
现在发出DeprecationWarning
,而不是PendingDeprecationWarning
。它们将在 Python 3.9 中被移除。(由 Serhiy Storchaka 在 bpo-29209 中贡献。)将不是
concurrent.futures.ThreadPoolExecutor
实例的对象传递给loop.set_default_executor()
已被弃用,并且将在 Python 3.9 中被禁止。(由 Elvis Pranskevichus 在 bpo-34075 中贡献。)xml.dom.pulldom.DOMEventStream
、wsgiref.util.FileWrapper
和fileinput.FileInput
的__getitem__()
方法已被弃用。这些方法的实现一直在忽略它们的 index 参数,而是返回下一个项目。(由 Berker Peksag 在 bpo-9372 中贡献。)
typing.NamedTuple
类已弃用_field_types
属性,转而使用具有相同信息的__annotations__
属性。(由 Raymond Hettinger 在 bpo-36320 中贡献。)ast
类Num
、Str
、Bytes
、NameConstant
和Ellipsis
被认为是已弃用的,并且将在未来的 Python 版本中被移除。应改用Constant
。(由 Serhiy Storchaka 在 bpo-32892 中贡献。)ast.NodeVisitor
方法visit_Num()
、visit_Str()
、visit_Bytes()
、visit_NameConstant()
和visit_Ellipsis()
现在已被弃用,并且在未来的 Python 版本中将不会被调用。添加visit_Constant()
方法来处理所有常量节点。(由 Serhiy Storchaka 在 bpo-36917 中贡献。)asyncio.coroutine()
装饰器 已被弃用,并且将在 3.10 版本中被移除。请使用async def
代替@asyncio.coroutine
。(由 Andrew Svetlov 在 bpo-36921 中贡献。)在
asyncio
中,显式传递 loop 参数已被弃用,并且将在 3.10 版本中移除,以下函数和类将受影响:asyncio.sleep()
,asyncio.gather()
,asyncio.shield()
,asyncio.wait_for()
,asyncio.wait()
,asyncio.as_completed()
,asyncio.Task
,asyncio.Lock
,asyncio.Event
,asyncio.Condition
,asyncio.Semaphore
,asyncio.BoundedSemaphore
,asyncio.Queue
,asyncio.create_subprocess_exec()
, 以及asyncio.create_subprocess_shell()
。显式地将协程对象传递给
asyncio.wait()
已被弃用,并且将在 3.11 版本中移除。(由 Yury Selivanov 在 bpo-34790 中贡献。)以下函数和方法在
gettext
模块中已被弃用:lgettext()
,ldgettext()
,lngettext()
和ldngettext()
。 它们返回编码后的字节,如果翻译后的字符串存在编码问题,您可能会遇到意外的 Unicode 相关异常。 最好使用在 Python 3 中返回 Unicode 字符串的替代方案。这些函数长期以来都存在问题。函数
bind_textdomain_codeset()
, 方法output_charset()
和set_output_charset()
,以及函数translation()
和install()
的 codeset 参数也被弃用,因为它们仅用于l*gettext()
函数。(由 Serhiy Storchaka 在 bpo-33710 中贡献。)threading.Thread
的isAlive()
方法已被弃用。(由 Donghee Na 在 bpo-35283 中贡献。)许多接受整数参数的内置和扩展函数现在将针对
Decimal
,Fraction
和任何其他只能通过损失转换为整数的对象(例如,具有__int__()
方法但没有__index__()
方法的对象)发出弃用警告。在未来版本中,它们将是错误。(由 Serhiy Storchaka 在 bpo-36048 中贡献。)弃用将以下参数作为关键字参数传递:
functools.partialmethod()
,weakref.finalize()
,profile.Profile.runcall()
,cProfile.Profile.runcall()
,bdb.Bdb.runcall()
,trace.Trace.runfunc()
和curses.wrapper()
中的 func 。unittest.TestCase.addCleanup()
中的 function 。submit()
方法中concurrent.futures.ThreadPoolExecutor
和concurrent.futures.ProcessPoolExecutor
的 fn 。contextlib.ExitStack.callback()
,contextlib.AsyncExitStack.callback()
和contextlib.AsyncExitStack.push_async_callback()
中的 callback 。multiprocessing.managers.Server
和multiprocessing.managers.SharedMemoryServer
的create()
方法中的 c 和 typeid。weakref.finalize()
中的 obj 。
在未来的 Python 版本中,它们将是 仅限位置参数。(由 Serhiy Storchaka 在 bpo-36492 中贡献。)
API 和功能移除¶
以下功能和 API 已从 Python 3.8 中移除
从 Python 3.3 开始,从
collections
导入 ABC 已被弃用,应该从collections.abc
导入。 从 collections 导入的能力被标记为在 3.8 中删除,但已推迟到 3.9。(请参阅 gh-81134。)在 Python 3.7 中已弃用的
macpath
模块已被删除。(由 Victor Stinner 在 bpo-35471 中贡献。)自 Python 3.3 起已弃用的函数
platform.popen()
已被删除:请改用os.popen()
。(由 Victor Stinner 在 bpo-35345 中贡献。)自 Python 3.3 起已弃用的函数
time.clock()
已被删除:请改用time.perf_counter()
或time.process_time()
,具体取决于您的需求,以获得明确定义的行为。(由 Matthias Bussonnier 在 bpo-36895 中贡献。)为了避免对
pyvenv
脚本所关联的 Python 解释器产生混淆,已移除pyvenv
脚本,改用python3.8 -m venv
。(由 Brett Cannon 在 bpo-25427 中贡献。)parse_qs
、parse_qsl
和escape
已从cgi
模块中移除。它们在 Python 3.2 或更早版本中已弃用。应该从urllib.parse
和html
模块导入。filemode
函数已从tarfile
模块中移除。它未被记录,并且自 Python 3.3 起已弃用。XMLParser
构造函数不再接受 *html* 参数。它从未生效,并且在 Python 3.4 中已弃用。所有其他参数现在都是仅关键字。(由 Serhiy Storchaka 在 bpo-29209 中贡献。)移除了
XMLParser
的doctype()
方法。(由 Serhiy Storchaka 在 bpo-29209 中贡献。)移除了“unicode_internal”编解码器。(由 Inada Naoki 在 bpo-36297 中贡献。)
sqlite3
模块的Cache
和Statement
对象不再向用户公开。(由 Aviv Palivoda 在 bpo-30262 中贡献。)fileinput.input()
和fileinput.FileInput()
的bufsize
关键字参数已被移除,该参数自 Python 3.6 起就被忽略并已弃用。bpo-36952(由 Matthias Bussonnier 贡献。)Python 3.7 中已弃用的函数
sys.set_coroutine_wrapper()
和sys.get_coroutine_wrapper()
已被移除;bpo-36933(由 Matthias Bussonnier 贡献。)
移植到 Python 3.8¶
本节列出了先前描述的更改和其他可能需要更改代码的错误修复。
Python 行为的更改¶
现在不允许在推导式和生成器表达式中使用 yield 表达式(包括
yield
和yield from
子句)(除了最左边的for
子句中的可迭代表达式)。(由 Serhiy Storchaka 在 bpo-10544 中贡献。)当标识检查(
is
和is not
)与某些类型的字面量(例如字符串、数字)一起使用时,编译器现在会产生SyntaxWarning
。这些在 CPython 中通常会意外地工作,但语言规范不保证。该警告建议用户改用相等性测试(==
和!=
)。(由 Serhiy Storchaka 在 bpo-34850 中贡献。)CPython 解释器在某些情况下可以吞噬异常。在 Python 3.8 中,这种情况发生的次数更少。特别是,从类型字典获取属性时引发的异常不再被忽略。(由 Serhiy Storchaka 在 bpo-35459 中贡献。)
从内置类型
bool
、int
、float
、complex
和标准库中的几个类中移除了__str__
实现。它们现在从object
继承__str__()
。因此,在这些类的子类中定义__repr__()
方法将影响它们的字符串表示形式。(由 Serhiy Storchaka 在 bpo-36793 中贡献。)在 AIX 上,
sys.platform
不再包含主版本号。它始终是'aix'
,而不是'aix3'
..'aix7'
。由于较旧的 Python 版本包含版本号,因此建议始终使用sys.platform.startswith('aix')
。(由 M. Felt 在 bpo-36588 中贡献。)如果解释器正在最终确定,则调用
PyEval_AcquireLock()
和PyEval_AcquireThread()
现在会终止当前线程,使它们与PyEval_RestoreThread()
、Py_END_ALLOW_THREADS()
和PyGILState_Ensure()
一致。如果不需要此行为,请通过检查_Py_IsFinalizing()
或sys.is_finalizing()
来保护调用。(由 Joannah Nanjekye 在 bpo-36475 中贡献。)
Python API 的更改¶
os.getcwdb()
函数现在在 Windows 上使用 UTF-8 编码,而不是 ANSI 代码页:有关其原理,请参阅 PEP 529。该函数在 Windows 上不再弃用。(由 Victor Stinner 在 bpo-37412 中贡献。)subprocess.Popen
现在可以在某些情况下使用os.posix_spawn()
以获得更好的性能。在适用于 Linux 的 Windows 子系统和 QEMU 用户仿真上,使用os.posix_spawn()
的Popen
构造函数不再在出现诸如“缺少程序”之类的错误时引发异常。相反,子进程会失败并返回非零returncode
。(由 Joannah Nanjekye 和 Victor Stinner 在 bpo-35537 中贡献。)subprocess.Popen
的 *preexec_fn* 参数不再与子解释器兼容。在子解释器中使用该参数现在会引发RuntimeError
。(由 Eric Snow 在 bpo-34651 中贡献,由 Christian Heimes 在 bpo-37951 中修改。)imap.IMAP4.logout()
方法不再静默忽略任意异常。(由 Victor Stinner 在 bpo-36348 中贡献。)自 Python 3.3 起已弃用的函数
platform.popen()
已被删除:请改用os.popen()
。(由 Victor Stinner 在 bpo-35345 中贡献。)当给定多峰数据时,
statistics.mode()
函数不再引发异常。相反,它返回输入数据中遇到的第一个众数。(由 Raymond Hettinger 在 bpo-35892 中贡献。)selection()
方法(属于tkinter.ttk.Treeview
类)不再接受参数。在 Python 3.6 中,使用参数来更改选择已被弃用。请使用专门的方法(如selection_set()
)来更改选择。(由 Serhiy Storchaka 在 bpo-31508 中贡献。)writexml()
、toxml()
和toprettyxml()
方法(属于xml.dom.minidom
),以及write()
方法(属于xml.etree
),现在会保留用户指定的属性顺序。(由 Diego Rojas 和 Raymond Hettinger 在 bpo-34160 中贡献。)以
'r'
标志打开的dbm.dumb
数据库现在是只读的。dbm.dumb.open()
使用'r'
和'w'
标志时,如果数据库不存在,则不再创建数据库。(由 Serhiy Storchaka 在 bpo-32749 中贡献。)在
XMLParser
的子类中定义的doctype()
方法将不再被调用,并且会发出RuntimeWarning
而不是DeprecationWarning
。请在目标上定义doctype()
方法来处理 XML 文档类型声明。(由 Serhiy Storchaka 在 bpo-29209 中贡献。)当自定义元类在传递给
type.__new__
的命名空间中没有提供__classcell__
条目时,现在会引发RuntimeError
。在 Python 3.6–3.7 中,会发出DeprecationWarning
。(由 Serhiy Storchaka 在 bpo-23722 中贡献。)cProfile.Profile
类现在可以用作上下文管理器。(由 Scott Sanderson 在 bpo-29235 中贡献。)shutil.copyfile()
,shutil.copy()
,shutil.copy2()
,shutil.copytree()
和shutil.move()
使用特定于平台的“快速复制”系统调用(请参阅 平台相关的有效复制操作 部分)。Windows 上
shutil.copyfile()
的默认缓冲区大小从 16 KiB 更改为 1 MiB。PyGC_Head
结构已完全更改。所有涉及结构成员的代码都应重写。(请参阅 bpo-33597。)PyInterpreterState
结构已被移至“内部”头文件(特别是 Include/internal/pycore_pystate.h)。不透明的PyInterpreterState
仍然作为公共 API(和稳定的 ABI)的一部分提供。文档指出该结构的任何字段都不是公共的,因此我们希望没有人使用它们。但是,如果您确实依赖一个或多个这些私有字段并且没有其他选择,请打开一个 BPO 问题。我们将努力帮助您进行调整(可能包括向公共 API 添加访问器函数)。(请参阅 bpo-35886。)mmap.flush()
方法现在在所有平台上成功时返回None
,在出错时引发异常。以前,其行为取决于平台:在 Windows 上,成功时返回非零值;出错时返回零值。在 Unix 上,成功时返回零值;出错时引发异常。(由 Berker Peksag 在 bpo-2122 中贡献。)xml.dom.minidom
和xml.sax
模块默认不再处理外部实体。(由 Christian Heimes 在 bpo-17239 中贡献。)从只读
dbm
数据库(dbm.dumb
,dbm.gnu
或dbm.ndbm
)中删除键会引发error
(dbm.dumb.error
,dbm.gnu.error
或dbm.ndbm.error
) 而不是KeyError
。(由 Xiang Zhang 在 bpo-33106 中贡献。)简化字面值的 AST。所有常量都将表示为
ast.Constant
实例。实例化旧类Num
、Str
、Bytes
、NameConstant
和Ellipsis
将返回一个Constant
的实例。(由 Serhiy Storchaka 在 bpo-32892 中贡献。)Windows 上的
expanduser()
现在优先使用USERPROFILE
环境变量,并且不使用HOME
,后者通常不为常规用户帐户设置。(由 Anthony Sottile 在 bpo-36264 中贡献。)异常
asyncio.CancelledError
现在继承自BaseException
而不是Exception
,并且不再继承自concurrent.futures.CancelledError
。(由 Yury Selivanov 在 bpo-32528 中贡献。)现在,当使用
asyncio.Task
的实例时,函数asyncio.wait_for()
可以正确等待取消操作。 之前,当达到timeout时,它会被取消并立即返回。(由 Elvis Pranskevichus 贡献,详见 bpo-32751。)现在,当将 ‘socket’ 传递给 name 参数时,函数
asyncio.BaseTransport.get_extra_info()
会返回一个可以安全使用的套接字对象。(由 Yury Selivanov 贡献,详见 bpo-37027。)asyncio.BufferedProtocol
已升级为稳定 API。
现在,Windows 上扩展模块和通过
ctypes
加载的 DLL 的 DLL 依赖项的解析更加安全。只会在系统路径、包含 DLL 或 PYD 文件的目录,以及通过add_dll_directory()
添加的目录中搜索加载时依赖项。具体来说,不再使用PATH
和当前工作目录,并且对它们的修改不再对正常的 DLL 解析产生任何影响。如果您的应用程序依赖这些机制,您应该检查add_dll_directory()
,如果它存在,则在加载库时使用它来添加您的 DLL 目录。 请注意,Windows 7 用户需要确保已安装 Windows 更新 KB2533623(安装程序也会验证这一点)。(由 Steve Dower 贡献,详见 bpo-36085。)在用纯 Python 实现替换 pgen 之后,与 pgen 相关的头文件和函数已被删除。(由 Pablo Galindo 贡献,详见 bpo-36623。)
types.CodeType
的构造函数在第二个位置(posonlyargcount)有一个新参数,以支持 PEP 570 中定义的位置参数。 第一个参数(argcount)现在表示位置参数的总数(包括仅限位置的参数)。types.CodeType
的新replace()
方法可用于使代码在未来保持兼容性。hmac.new()
的参数digestmod
不再默认使用 MD5 摘要。
C API 中的更改¶
PyCompilerFlags
结构体获得了一个新的 cf_feature_version 字段。 它应该初始化为PY_MINOR_VERSION
。 该字段默认情况下被忽略,并且当且仅当在 cf_flags 中设置了PyCF_ONLY_AST
标志时才使用。(由 Guido van Rossum 贡献,详见 bpo-35766。)PyEval_ReInitThreads()
函数已从 C API 中删除。 不应显式调用它:请改用PyOS_AfterFork_Child()
。(由 Victor Stinner 贡献,详见 bpo-36728。)在 Unix 上,C 扩展程序不再链接到 libpython,除非是在 Android 和 Cygwin 上。当 Python 被嵌入时,
libpython
不得使用RTLD_LOCAL
加载,而应使用RTLD_GLOBAL
加载。 以前,使用RTLD_LOCAL
,已经无法加载未链接到libpython
的 C 扩展程序,例如由Modules/Setup
的*shared*
部分构建的标准库的 C 扩展程序。(由 Victor Stinner 贡献,详见 bpo-21536。)现在,在解析或构建值时(例如,
PyArg_ParseTuple()
,Py_BuildValue()
,PyObject_CallFunction()
等)使用不带定义PY_SSIZE_T_CLEAN
的格式的#
变体,会引发DeprecationWarning
。它将在 3.10 或 4.0 中删除。有关详细信息,请阅读 解析参数和构建值。(由 Inada Naoki 贡献,详见 bpo-36381。)堆分配类型(例如使用
PyType_FromSpec()
创建的类型)的实例保留对其类型对象的引用。 增加这些类型对象的引用计数已从PyType_GenericAlloc()
移至更底层的函数,PyObject_Init()
和PyObject_INIT()
。 这使得通过PyType_FromSpec()
创建的类型在托管代码中的行为与其他类类似。静态分配类型 不受影响。
在绝大多数情况下,不应有任何副作用。但是,在分配实例后手动增加引用计数(可能是为了解决该错误)的类型现在可能会变为永生。为了避免这种情况,这些类需要在实例释放期间调用 Py_DECREF 来释放类型对象。
要将这些类型正确移植到 3.8,请应用以下更改
删除分配实例后类型对象的
Py_INCREF
(如果有)。这可能会在调用PyObject_New
,PyObject_NewVar
,PyObject_GC_New()
,PyObject_GC_NewVar()
或任何使用PyObject_Init()
或PyObject_INIT()
的其他自定义分配器之后发生。示例
static foo_struct * foo_new(PyObject *type) { foo_struct *foo = PyObject_GC_New(foo_struct, (PyTypeObject *) type); if (foo == NULL) return NULL; #if PY_VERSION_HEX < 0x03080000 // Workaround for Python issue 35810; no longer necessary in Python 3.8 PY_INCREF(type) #endif return foo; }
确保堆分配类型的所有自定义
tp_dealloc
函数都会减少类型的引用计数。示例
static void foo_dealloc(foo_struct *instance) { PyObject *type = Py_TYPE(instance); PyObject_GC_Del(instance); #if PY_VERSION_HEX >= 0x03080000 // This was not needed before Python 3.8 (Python issue 35810) Py_DECREF(type); #endif }
(由 Eddie Elizondo 贡献,详见 bpo-35810。)
Py_DEPRECATED()
宏已为 MSVC 实现。 现在,该宏必须放在符号名称之前。示例
Py_DEPRECATED(3.8) PyAPI_FUNC(int) Py_OldFunction(void);
(由 Zackery Spytz 贡献,详见 bpo-33407。)
解释器不再假装支持跨功能版本的扩展类型的二进制兼容性。第三方扩展模块导出的
PyTypeObject
应该具有当前 Python 版本中期望的所有插槽,包括tp_finalize
(读取tp_finalize
之前不再检查Py_TPFLAGS_HAVE_FINALIZE
)。(由 Antoine Pitrou 贡献,详见 bpo-32388。)
现在,函数
PyNode_AddChild()
和PyParser_AddToken()
接受两个额外的int
参数 end_lineno 和 end_col_offset。不再在常规 Windows 发行版中包含
libpython38.a
文件,以允许 MinGW 工具直接链接到python38.dll
。如果您需要此文件,可以使用gendef
和dlltool
工具生成它,这些工具是 MinGW binutils 包的一部分gendef - python38.dll > tmp.def dlltool --dllname python38.dll --def tmp.def --output-lib libpython38.a
已安装的
pythonXY.dll
的位置将取决于安装选项以及 Windows 的版本和语言。有关更多信息,请参见 在 Windows 上使用 Python。生成的库应与pythonXY.lib
放在同一目录中,该目录通常是 Python 安装下的libs
目录。(由 Steve Dower 贡献,详见 bpo-37351。)
CPython 字节码更改¶
解释器循环已得到简化,通过将展开代码块堆栈的逻辑移至编译器中。现在,编译器会发出显式指令来调整值堆栈,并为
break
、continue
和return
调用清理代码。移除了操作码
BREAK_LOOP
、CONTINUE_LOOP
、SETUP_LOOP
和SETUP_EXCEPT
。添加了新的操作码ROT_FOUR
、BEGIN_FINALLY
、CALL_FINALLY
和POP_FINALLY
。更改了END_FINALLY
和WITH_CLEANUP_START
的行为。(由 Mark Shannon、Antoine Pitrou 和 Serhiy Storchaka 在 bpo-17611 中贡献。)
添加了新的操作码
END_ASYNC_FOR
,用于处理在async for
循环中等待下一个项目时引发的异常。(由 Serhiy Storchaka 在 bpo-33041 中贡献。)现在,
MAP_ADD
期望值作为堆栈中的第一个元素,键作为第二个元素。做出此更改是为了确保在字典推导式中始终先评估键,然后评估值,正如 PEP 572 所建议的那样。(由 Jörn Heissler 在 bpo-35224 中贡献。)
演示和工具¶
添加了一个基准测试脚本,用于测量访问各种变量的方式所需的时间:Tools/scripts/var_access_benchmark.py
。(由 Raymond Hettinger 在 bpo-35884 中贡献。)
以下是自 Python 3.3 以来的性能改进摘要
Python version 3.3 3.4 3.5 3.6 3.7 3.8
-------------- --- --- --- --- --- ---
Variable and attribute read access:
read_local 4.0 7.1 7.1 5.4 5.1 3.9
read_nonlocal 5.3 7.1 8.1 5.8 5.4 4.4
read_global 13.3 15.5 19.0 14.3 13.6 7.6
read_builtin 20.0 21.1 21.6 18.5 19.0 7.5
read_classvar_from_class 20.5 25.6 26.5 20.7 19.5 18.4
read_classvar_from_instance 18.5 22.8 23.5 18.8 17.1 16.4
read_instancevar 26.8 32.4 33.1 28.0 26.3 25.4
read_instancevar_slots 23.7 27.8 31.3 20.8 20.8 20.2
read_namedtuple 68.5 73.8 57.5 45.0 46.8 18.4
read_boundmethod 29.8 37.6 37.9 29.6 26.9 27.7
Variable and attribute write access:
write_local 4.6 8.7 9.3 5.5 5.3 4.3
write_nonlocal 7.3 10.5 11.1 5.6 5.5 4.7
write_global 15.9 19.7 21.2 18.0 18.0 15.8
write_classvar 81.9 92.9 96.0 104.6 102.1 39.2
write_instancevar 36.4 44.6 45.8 40.0 38.9 35.5
write_instancevar_slots 28.7 35.6 36.1 27.3 26.6 25.7
Data structure read access:
read_list 19.2 24.2 24.5 20.8 20.8 19.0
read_deque 19.9 24.7 25.5 20.2 20.6 19.8
read_dict 19.7 24.3 25.7 22.3 23.0 21.0
read_strdict 17.9 22.6 24.3 19.5 21.2 18.9
Data structure write access:
write_list 21.2 27.1 28.5 22.5 21.6 20.0
write_deque 23.8 28.7 30.1 22.7 21.8 23.5
write_dict 25.9 31.4 33.3 29.3 29.2 24.7
write_strdict 22.9 28.4 29.9 27.5 25.2 23.1
Stack (or queue) operations:
list_append_pop 144.2 93.4 112.7 75.4 74.2 50.8
deque_append_pop 30.4 43.5 57.0 49.4 49.2 42.5
deque_append_popleft 30.8 43.7 57.3 49.7 49.7 42.8
Timing loop:
loop_overhead 0.3 0.5 0.6 0.4 0.3 0.3
这些基准测试是在 Intel® Core™ i7-4960HQ 处理器上测量的,该处理器运行的是在 python.org 上找到的 macOS 64 位版本。基准测试脚本以纳秒为单位显示时间。
Python 3.8.1 中的重大更改¶
由于存在重大的安全问题,不再支持 asyncio.loop.create_datagram_endpoint()
的 *reuse_address* 参数。这是因为 UDP 中套接字选项 SO_REUSEADDR
的行为。有关更多详细信息,请参阅 loop.create_datagram_endpoint()
的文档。(由 Kyle Stanley、Antoine Pitrou 和 Yury Selivanov 在 bpo-37228 中贡献。)
Python 3.8.2 中的重大更改¶
修复了 shutil.copytree()
的 ignore
回调中的一个回归错误。参数类型现在再次为 str 和 List[str]。(由 Manuel Barkhau 和 Giampaolo Rodola 在 gh-83571 中贡献。)
Python 3.8.3 中的重大更改¶
更新了 __future__
模块中 future 标志的常量值,以防止与编译器标志发生冲突。以前,PyCF_ALLOW_TOP_LEVEL_AWAIT
与 CO_FUTURE_DIVISION
冲突。(由 Batuhan Taskaya 在 gh-83743 中贡献。)
Python 3.8.8 中的重大更改¶
早期的 Python 版本允许在 urllib.parse.parse_qs()
和 urllib.parse.parse_qsl()
中使用 ;
和 &
作为查询参数分隔符。出于安全考虑,并为了符合较新的 W3C 建议,此行为已更改为仅允许单个分隔符键,默认使用 &
。此更改还会影响 cgi.parse()
和 cgi.parse_multipart()
,因为它们在内部使用了受影响的函数。有关更多详细信息,请参阅它们各自的文档。(由 Adam Goldschmidt、Senthil Kumaran 和 Ken Jin 在 bpo-42967 中贡献。)
Python 3.8.9 中的重大更改¶
一个安全修复程序更改了 ftplib.FTP
的行为,使其在设置被动数据通道时不信任远程服务器发送的 IPv4 地址。我们改为重用 ftp 服务器的 IP 地址。对于需要旧行为的异常代码,请将您的 FTP 实例上的 trust_server_pasv_ipv4_address
属性设置为 True
。(请参阅 gh-87451)
Python 3.8.10 中的重大更改¶
macOS 11.0 (Big Sur) 和 Apple Silicon Mac 支持¶
从 3.8.10 开始,Python 现在支持在 macOS 11 (Big Sur) 和基于 ARM64
架构的 Apple Silicon Mac 上构建和运行。现在可以使用新的通用构建变体 universal2
,以在一个可执行文件集中本地支持 ARM64
和 Intel 64
。请注意,此从 Python 3.9 的向后移植中不包含对“弱链接”的支持,即构建面向较新 macOS 版本的二进制文件,这些二进制文件也将在较旧版本上正确运行,方法是在运行时测试缺失的功能;要支持一系列 macOS 版本,请继续以该范围中最旧的版本为目标并在此版本上进行构建。
(最初由 Ronald Oussoren 和 Lawrence D’Anna 在 gh-85272 中贡献,由 FX Coudert 和 Eli Rykoff 进行修复,并由 Maxime Bélanger 和 Ned Deily 向后移植到 3.8)
Python 3.8.10 中的重大更改¶
urllib.parse¶
URL 的某些部分中存在换行符或制表符会导致某些形式的攻击。根据更新 RFC 3986 的 WHATWG 规范,urllib.parse
中的解析器会从 URL 中删除 ASCII 换行符 \n
、 \r
和制表符 \t
,从而防止此类攻击。删除的字符由新的模块级别变量 urllib.parse._UNSAFE_URL_BYTES_TO_REMOVE
控制。(请参阅 bpo-43882)
Python 3.8.12 中的重大更改¶
Python API 中的更改¶
从 Python 3.8.12 开始,ipaddress
模块不再接受 IPv4 地址字符串中的任何前导零。前导零具有歧义,并且会被某些库解释为八进制表示法。例如,旧函数 socket.inet_aton()
将前导零视为八进制表示法。glibc 实现的现代 inet_pton()
不接受任何前导零。
(最初由 Christian Heimes 在 bpo-36384 中贡献,并由 Achraf Merzouki 反向移植到 3.8。)
3.8.14 中的重要安全特性¶
在 2(二进制)、4、8(八进制)、16(十六进制)或 32 之外的进制(例如 10 进制)中,int
和 str
之间的转换,如果字符串形式的位数超过限制,现在会引发 ValueError
,以避免因算法复杂度而可能造成的拒绝服务攻击。这是对 CVE 2020-10735 的缓解措施。可以通过环境变量、命令行标志或 sys
API 来配置或禁用此限制。请参阅 整数字符串转换长度限制 文档。默认限制是字符串形式的 4300 位数字。
3.8.17 中的重要更改¶
tarfile¶
tarfile
中的提取方法和shutil.unpack_archive()
有一个新的 filter 参数,该参数允许限制 tar 的特性,这些特性可能会令人惊讶或危险,例如在目标目录之外创建文件。有关详细信息,请参阅 提取过滤器。在 Python 3.12 中,如果不使用 filter 参数,将显示DeprecationWarning
。在 Python 3.14 中,默认值将切换为'data'
。(由 Petr Viktorin 在 PEP 706 中贡献。)