Python 3.8 的新特性 — Python 文档
Python 3.8 中的新功能
- 编辑
- 雷蒙德·赫廷格
本文解释了 Python 3.8 中与 3.7 相比的新特性。 有关完整详细信息,请参阅 变更日志 。
摘要 – 发布亮点
新特性
赋值表达式
有新语法 :=
将值分配给变量作为更大表达式的一部分。 由于它与 海象 的眼睛和象牙相似,因此被亲切地称为“海象运算符”。
在这个例子中,赋值表达式有助于避免调用 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]
尽量限制使用 walrus operator 来清理案例,以降低复杂性并提高可读性。
有关完整说明,请参阅 PEP 572。
(由 Emily Morehouse 在 中提供:issue:`35224`。)
仅位置参数
有一个新的函数参数语法 /
指示某些函数参数必须在位置上指定,不能用作关键字参数。 这与 help()
为使用 Larry Hastings 的 Argument Clinic 工具注释的 C 函数显示的符号相同。
在以下示例中,参数 a 和 b 仅是位置参数,而 c 或 d 可以是位置参数或关键字,而 [ X149X]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 在 中提供:issue:`36540`。)
编译字节码文件的并行文件系统缓存
新的 PYTHONPYCACHEPREFIX 设置(也可用作 -X pycache_prefix
)将隐式字节码缓存配置为使用单独的并行文件系统树,而不是每个源目录中的默认 __pycache__
子目录。
缓存的位置报告在 sys.pycache_prefix(None 表示默认位置在 __pycache__
子目录中)。
(由 Carl Meyer 在 中提供:问题:`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 在 中提供:问题:`36465`。)
在 Unix 上,除 Android 和 Cygwin 外,C 扩展不再链接到 libpython。 现在,静态链接的 Python 可以加载使用共享库 Python 构建的 C 扩展。 (由 Victor Stinner 在 中提供:问题:`21536`。)
在 Unix 上,当 Python 在调试模式下构建时,import 现在还会查找在发布模式下编译的 C 扩展以及使用稳定 ABI 编译的 C 扩展。 (由 Victor Stinner 在 中提供:问题:`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 在 中提供:问题:`36721`。)
f-strings 支持 = 用于自记录表达式和调试
向 f-strings 添加了 =
说明符。 诸如 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
(由埃里克 V 提供。 中的 Smith 和 Larry Hastings:问题:`36817`。)
PEP 578:Python 运行时审计挂钩
PEP 添加了审计挂钩和已验证的开放挂钩。 两者都可以从 Python 和本机代码中获得,允许用纯 Python 代码编写的应用程序和框架利用额外的通知,同时还允许嵌入者或系统管理员部署始终启用审计的 Python 构建。
有关完整详细信息,请参阅 PEP 578。
PEP 587:Python 初始化配置
PEP 587 添加了一个新的 C API 来配置 Python 初始化,提供对整个配置的更好控制和更好的错误报告。
新结构:
新功能:
PyConfig_Clear()
PyConfig_InitIsolatedConfig()
PyConfig_InitPythonConfig()
PyConfig_Read()
PyConfig_SetArgv()
PyConfig_SetBytesArgv()
PyConfig_SetBytesString()
PyConfig_SetString()
PyPreConfig_InitIsolatedConfig()
PyPreConfig_InitPythonConfig()
PyStatus_Error()
PyStatus_Exception()
PyStatus_Exit()
PyStatus_IsError()
PyStatus_IsExit()
PyStatus_NoMemory()
PyStatus_Ok()
PyWideStringList_Append()
PyWideStringList_Insert()
Py_BytesMain()
Py_ExitStatusException()
Py_InitializeFromConfig()
Py_PreInitialize()
Py_PreInitializeFromArgs()
Py_PreInitializeFromBytesArgs()
Py_RunMain()
该 PEP 还在这些内部结构中添加了 _PyRuntimeState.preconfig
(PyPreConfig 类型)和 PyInterpreterState.config
(PyConfig 类型)字段。 PyInterpreterState.config
成为新的参考配置,替换全局配置变量和其他私有变量。
有关文档,请参阅 Python 初始化配置 。
有关完整说明,请参阅 PEP 587。
(由 Victor Stinner 在 中提供:问题:`36763`。)
PEP 590:Vectorcall:CPython 的快速调用协议
矢量调用协议被添加到Python/C API。 它旨在形式化已经为各种类完成的现有优化。 任何实现可调用的静态类型都可以使用此协议。
这是目前临时的。 目的是使其在 Python 3.9 中完全公开。
有关完整说明,请参阅 PEP 590。
(由 Jeroen Demeyer、Mark Shannon 和 Petr Viktorin 在 :issue:`36974` 中提供。)
带外数据缓冲区的 Pickle 协议 5
当 pickle 用于在 Python 进程之间传输大数据以利用多核或多机处理时,重要的是通过减少内存副本来优化传输,并可能通过应用自定义技术例如依赖于数据的压缩。
pickle 协议 5 引入了对带外缓冲区的支持,其中 PEP 3118 兼容的数据可以与主pickle 流分开传输,酌情决定通信层的。
有关完整说明,请参阅 PEP 574。
(由 Antoine Pitrou 在 中提供:issue:`36785`。)
其他语言更改
由于实现问题,continue 语句在 finally 子句中是非法的。 在 Python 3.8 中,这个限制被取消了。 (由 Serhiy Storchaka 在 中提供:issue:`32489`。)
bool、int 和 fractions.Fraction 类型现在有一个 as_integer_ratio() 方法,类似于 float[ X146X] 和 decimal.Decimal。 这个次要的 API 扩展使得编写
numerator, denominator = x.as_integer_ratio()
并使其跨多种数字类型工作成为可能。 (由 Lisa Roach 在 :issue:`33073` 和 Raymond Hettinger 在 :issue:`37819` 中贡献。)int、float 和 complex 的构造函数现在将使用 __index__() 特殊方法(如果可用)和相应的方法 __int__()、__float__() 或 __complex__() 不可用。 (由 Serhiy Storchaka 在 :issue:`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 在 中提供:issue:`30688`。)
dict 和 dictviews 现在可以使用 reversed() 以相反的插入顺序迭代。 (由 Rémi Lapeyre 在 中提供:issue:`33462`。)
进一步限制了函数调用中关键字名称的语法。 特别是,不再允许使用
f((keyword)=arg)
。 它决不允许在关键字参数赋值项的左侧出现多个裸名。 (由 Benjamin Peterson 在 中提供:issue:`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 在 :issue:`32117` 中提供。)
当诸如
[(10, 20) (30, 40)]
之类的代码中缺少逗号时,编译器会显示一个 SyntaxWarning 并提供有用的建议。 这改进了只有 TypeError 指示第一个元组不可调用。 (由 Serhiy Storchaka 在 中提供:issue:`15248`。)datetime.date 或 datetime.datetime 和 datetime.timedelta 对象的子类之间的算术运算现在返回子类的实例,而不是基类。 这也会影响其实现(直接或间接)使用 datetime.timedelta 算法的操作的返回类型,例如 astimezone()。 (由 Paul Ganssle 在 :issue:`32417` 中提供。)
当 Python 解释器被 Ctrl-C (SIGINT) 中断并且产生的 KeyboardInterrupt 异常未被捕获时,Python 进程现在通过 SIGINT 信号或正确的退出代码退出,以便调用进程可以检测到它因 Ctrl-C 而死亡。 POSIX 和 Windows 上的 Shell 使用它来正确终止交互式会话中的脚本。 (由 Google 通过 Gregory P. 中的史密斯:问题:`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 在 中提供:问题:`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 在 :issue:`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 在 中提供:issue:`35224`。)
object.__reduce__() 方法现在可以返回一个长度为 2 到 6 个元素的元组。 以前,五个是极限。 新的可选的第六个元素是一个带有
(obj, state)
签名的可调用元素。 这允许直接控制特定对象的状态更新行为。 如果不是 None,这个可调用对象将优先于对象的__setstate__()
方法。 (由 Pierre Glaser 和 Olivier Grisel 在 中提供:issue:`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. 供稿) 中的库姆斯:问题:`34632`。)
改进的模块
AST
AST 节点现在具有 end_lineno
和 end_col_offset
属性,它们给出了节点末端的精确位置。 (这仅适用于具有 lineno
和 col_offset
属性的节点。)
新函数 ast.get_source_segment() 返回特定 AST 节点的源代码。
(由 Ivan Levkivskyi 在 :issue:`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 在 中提供:issue:`35766`。)
异步
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 在 :issue:`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 在 中提供:issue:`37028`。)
异常 asyncio.CancelledError 现在继承自 BaseException 而不是 Exception,并且不再继承自 concurrent.futures.CancelledError。 (由 Yury Selivanov 在 :issue:`32528` 中贡献。)
在 Windows 上,默认事件循环现在是 ProactorEventLoop。 (由 Victor Stinner 在 中提供:问题:`34687`。)
ProactorEventLoop 现在也支持 UDP。 (由 Adam Meily 和 Andrew Svetlov 在 :issue:`29883` 中贡献。)
ProactorEventLoop 现在可以被 KeyboardInterrupt(“CTRL+C”)打断。 (由 Vladimir Matveev 在 :issue:`23057` 中贡献。)
添加了 asyncio.Task.get_coro(),用于在 asyncio.Task 中获取包装的协程。 (由 Alex Grönholm 在 :issue:`36999` 中提供。)
现在可以命名异步任务,方法是将 name
关键字参数传递给 asyncio.create_task() 或 create_task() 事件循环方法,或者通过调用set_name() 任务对象上的方法。 任务名称在 asyncio.Task 的 repr()
输出中可见,也可以使用 get_name() 方法检索。 (由 Alex Grönholm 在 :issue:`34270` 中提供。)
添加了对 Happy Eyeballs 到 asyncio.loop.create_connection()
的支持。 为了指定行为,添加了两个新参数:happy_eyeballs_delay 和 interleave。 Happy Eyeballs 算法通过尝试同时使用 IPv4 和 IPv6 进行连接来提高支持 IPv4 和 IPv6 的应用程序的响应能力。 (由 中的 twinteroid 大使提供:issue:`33530`。)
内置函数
compile() 内置已改进以接受 ast.PyCF_ALLOW_TOP_LEVEL_AWAIT
标志。 通过这个新标志,compile() 将允许顶级 await
、async for
和 async with
构造,这些构造通常被认为是无效的语法。 然后可以返回标有 CO_COROUTINE
标志的异步代码对象。 (由 Matthias Bussonnier 在 中提供:issue:`34616`)
收藏
collections.namedtuple() 的 _asdict() 方法现在返回 dict 而不是 collections.OrderedDict。 这是有效的,因为从 Python 3.7 开始,常规字典就保证了排序。 如果需要 OrderedDict
的额外功能,建议的补救措施是将结果转换为所需的类型:OrderedDict(nt._asdict())
。 (由 Raymond Hettinger 在 中提供:issue:`35864`。)
个人资料
cProfile.Profile 类现在可以用作上下文管理器。 通过运行来分析代码块:
import cProfile
with cProfile.Profile() as profiler:
# code to be profiled
...
(由 Scott Sanderson 在 中提供:issue:`29235`。)
文件
csv.DictReader 现在返回 dict 的实例而不是 collections.OrderedDict。 该工具现在速度更快,使用的内存更少,同时仍保留字段顺序。 (由 Michael Selik 在 :issue:`34003` 中贡献。)
类型
在 Windows 上,CDLL 和子类现在接受 winmode 参数来指定底层 LoadLibraryEx
调用的标志。 默认标志设置为仅从受信任的位置加载 DLL 依赖项,包括存储 DLL 的路径(如果使用完整或部分路径加载初始 DLL)和由 add_dll_directory() 添加的路径. (由 Steve Dower 在 中提供:issue:`36085`。)
约会时间
添加了新的替代构造函数 datetime.date.fromisocalendar() 和 datetime.datetime.fromisocalendar(),它们分别构造了 date
和 datetime 对象来自 ISO 年、周数和工作日; 这些是每个类的 isocalendar
方法的逆。 (由 Paul Ganssle 在 :issue:`36004` 中提供。)
功能工具
functools.lru_cache() 现在可以用作直接装饰器,而不是用作返回装饰器的函数。 所以现在支持这两个:
@lru_cache
def f(x):
...
@lru_cache(maxsize=256)
def f(x):
...
(由 Raymond Hettinger 在 中提供:issue:`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 在 中提供:issue:`21145`)
添加了一个新的 functools.singledispatchmethod() 装饰器,使用 single dispatch 将方法转换为 泛型函数 :
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 在 中提供:issue:`32380`)
压缩包
将 mtime 参数添加到 gzip.compress() 以获得可重现的输出。 (由 Guo Ci Teo 在 中提供:issue:`34898`。)
对于某些类型的无效或损坏的 gzip 文件,现在会引发 BadGzipFile 异常而不是 OSError。 (由 Filip Gruszczyński、Michele Orrù 和 Zackery Spytz 在 :issue:`6584` 中贡献。)
空闲和空闲库
N 行(默认为 50)的输出被压缩到一个按钮。 N 可以在 Settings 对话框的 General 页面的 PyShell 部分中更改。 右键单击输出可以压缩更少但可能超长的行。 可以通过双击按钮或右键单击按钮将压缩的输出扩展到剪贴板或单独的窗口。 (由 Tal Einat 在 中提供:问题:`1529353`。)
将“运行自定义”添加到“运行”菜单以运行具有自定义设置的模块。 输入的任何命令行参数都会添加到 sys.argv。 它们还会重新出现在下一次自定义运行的框中。 还可以抑制正常的Shell主模块重启。 (由 Cheryl Sabella、Terry Jan Reedy 和其他人在 :issue:`5680` 和 :issue:`37627` 中贡献。)
为空闲编辑器窗口添加了可选的行号。 除非在配置对话框的“常规”选项卡中进行了其他设置,否则 Windows 将在没有行号的情况下打开。 现有窗口的行号在选项菜单中显示和隐藏。 (由 Tal Einat 和 Saimadhav Heblikar 在 :issue:`17535` 中提供。)
操作系统本机编码现在用于在 Python 字符串和 Tcl 对象之间进行转换。 这允许 IDLE 使用表情符号和其他非 BMP 字符。 这些字符可以显示或复制粘贴到剪贴板或从剪贴板粘贴。 将字符串从 Tcl 转换为 Python 并返回现在永远不会失败。 (很多人为此工作了八年,但问题最终由 Serhiy Storchaka 在 :issue:`13153` 中解决。)
3.8.1 中的新功能:
添加选项以关闭光标闪烁。 (由 Zackery Spytz 在 中提供:issue:`4603`。)
Escape 键现在关闭 IDLE 完成窗口。 (由 Johnny Najera 在 中提供:issue:`38944`。)
上述更改已向后移植到 3.7 维护版本。
将关键字添加到模块名称完成列表中。 (由特里 J。 中的 Reedy:问题:`37765`。)
检查
inspect.getdoc() 函数现在可以找到 __slots__
的文档字符串,如果该属性是 dict ,其中值是文档字符串。 这提供了类似于我们已有的 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 在 中提供:issue:`36326`。)
io
在开发模式 (-X env
) 和调试版本中,如果 close()
方法失败,io.IOBase 终结器现在会记录异常。 默认情况下,在发布版本中会以静默方式忽略异常。 (由 Victor Stinner 在 中提供:issue:`18748`。)
迭代工具
itertools.accumulate() 函数添加了一个选项 initial 关键字参数来指定初始值:
>>> from itertools import accumulate
>>> list(accumulate([10, 5, 30, 15], initial=1000))
[1000, 1010, 1015, 1045, 1060]
(由 Lisa Roach 在 中提供:问题:`34659`。)
日志记录
将 force 关键字参数添加到 logging.basicConfig() 设置为 true 时,在执行其他参数指定的配置之前,删除并关闭附加到根记录器的任何现有处理程序.
这解决了一个长期存在的问题。 一旦调用了记录器或 basicConfig(),随后对 basicConfig() 的调用将被默默忽略。 这使得使用交互式提示或 Jupyter 笔记本更新、试验或教授各种日志配置选项变得困难。
(由 Raymond Hettinger 建议,由 Dong-hee Na 实施,并由 Vinay Sajip 在 :issue:`33897` 中审查。)
数学
添加了新函数 math.dist() 用于计算两点之间的欧几里德距离。 (由 Raymond Hettinger 在 中提供:issue:`33089`。)
扩展了 math.hypot() 函数以处理多个维度。 以前,它只支持二维情况。 (由 Raymond Hettinger 在 中提供:issue:`33089`。)
添加了新函数 math.prod(),作为与 sum() 类似的函数,该函数返回“起始”值(默认值:1)乘以可迭代数字的乘积:
>>> prior = 0.8
>>> likelihoods = [0.625, 0.84, 0.30]
>>> math.prod(likelihoods, start=prior)
0.126
(由 Pablo Galindo 在 中提供:issue:`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 在 :issue:`37128`、:issue:`37178` 和 :issue:` 中贡献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 在 :issue:`36887` 中贡献。)
函数 math.factorial() 不再接受类似 int 的参数。 (由 Pablo Galindo 在 中提供:issue:`33083`。)
多处理
添加了新的 multiprocessing.shared_memory 模块。 (由 Davin Potts 在 中提供:问题:`35813`。)
在 macOS 上,现在默认使用 spawn 启动方法。 (由 Victor Stinner 在 中提供:问题:`33725`。)
操作系统
在 Windows 上添加了新函数 add_dll_directory(),用于在使用 ctypes 导入扩展模块或加载 DLL 时提供本机依赖项的额外搜索路径。 (由 Steve Dower 在 中提供:issue:`36085`。)
添加了一个新的 os.memfd_create() 函数来封装 memfd_create()
系统调用。 (由 Zackery Spytz 和 Christian Heimes 在 中提供:issue:`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
的代码将继续将连接视为目录,而处理来自 [ X200X]os.readlink() 现在可以将结点视为链接。
(由 Steve Dower 在 中提供:issue:`37834`。)
操作系统路径
os.path 函数返回布尔结果,如 exists(), lexists(), isdir(), isfile ()、islink() 和 ismount() 现在返回 False
而不是引发 ValueError 或其子类 UnicodeEncodeError 和 UnicodeDecodeError 用于包含无法在操作系统级别表示的字符或字节的路径。 (由 Serhiy Storchaka 在 中提供:issue:`33721`。)
Windows 上的 expanduser() 现在更喜欢 USERPROFILE
环境变量,并且不使用 HOME
,通常不会设置对于普通用户帐户。 (由 Anthony Sottile 在 中提供:issue:`36264`。)
isdir() 在 Windows 上不再返回 True
以获取指向不存在目录的链接。
Windows 上的 realpath() 现在解析重解析点,包括符号链接和目录连接。
(由 Steve Dower 在 中提供:issue:`37834`。)
路径库
pathlib.Path 返回布尔结果的方法,如 exists(), is_dir(), is_file(), is_mount ()、is_symlink()、is_block_device()、is_char_device()、is_fifo()[X224X1]、[isX_socket1] () 现在返回 False
而不是引发 ValueError 或其子类 UnicodeEncodeError 对于包含无法在操作系统级别表示的字符的路径。 (由 Serhiy Storchaka 在 中提供:issue:`33721`。)
添加了 pathlib.Path.link_to(),它创建了一个指向路径的硬链接。 (由 Joannah Nanjekye 在 中提供:issue:`26978`)
泡菜
pickle 扩展 C 优化的 Pickle 现在可以通过定义特殊的 reducer_override() 方法来覆盖函数和类的酸洗逻辑。 (由 Pierre Glaser 和 Olivier Grisel 在 中提供:issue:`35900`。)
库
添加了新的 plistlib.UID 并启用了对读取和写入 NSKeyedArchiver 编码的二进制 plist 的支持。 (由 Jon Janzen 在 中提供:issue:`26707`。)
打印
pprint 模块向多个函数添加了 sort_dicts 参数。 默认情况下,这些函数会在渲染或打印之前继续对字典进行排序。 但是,如果 sort_dicts 设置为 false,则字典会保留插入键的顺序。 这对于在调试期间与 JSON 输入进行比较非常有用。
此外,还有一个方便的新函数,pprint.pp() 类似于 pprint.pprint() 但 sort_dicts 默认为 [ X156X]:
>>> 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 在 :issue:`30670` 中提供。)
休蒂尔
shutil.copytree() 现在接受一个新的 dirs_exist_ok
关键字参数。 (由 Josh Bronson 在 :issue:`20849` 中提供。)
shutil.make_archive() 现在默认为新存档的现代 pax (POSIX.1-2001) 格式,以提高可移植性和标准一致性,继承自 tarfile 模块的相应更改. (由 CAM 提供 中的 Gerlach:问题:`30661`。)
shutil.rmtree() 在 Windows 上现在删除目录连接而不先递归删除它们的内容。 (由 Steve Dower 在 中提供:issue:`37834`。)
插座
添加了 create_server() 和 has_dualstack_ipv6() 便利函数来自动化创建服务器套接字时通常涉及的必要任务,包括在同一套接字上接受 IPv4 和 IPv6 连接。 (由 Giampaolo Rodolà 在 :issue:`17561` 中提供。)
socket.if_nameindex()、socket.if_nametoindex() 和 socket.if_indextoname() 函数已在 Windows 上实现。 (由 Zackery Spytz 在 中提供:issue:`37007`。)
ssl
添加了 post_handshake_auth 以启用和 verify_client_post_handshake() 以启动 TLS 1.3 握手后身份验证。 (由 Christian Heimes 在 中提供:issue:`34670`。)
统计数据
添加 statistics.fmean() 作为 statistics.mean() 的更快浮点变体。 (由 Raymond Hettinger 和 Steven D'Aprano 在 :issue:`35904` 中提供。)
添加了 statistics.geometric_mean()(由 Raymond Hettinger 在 中贡献:issue:`27181`。)
添加了 statistics.multimode() 返回最常见值的列表。 (由 Raymond Hettinger 在 中提供:issue:`35892`。)
添加了 statistics.quantiles() 将数据或分布划分为等概率区间(例如 四分位数、十分位数或百分位数)。 (由 Raymond Hettinger 在 中提供:issue:`36546`。)
添加了 statistics.NormalDist,一种用于创建和操作随机变量正态分布的工具。 (由 Raymond Hettinger 在 中提供:issue:`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.unraisablehook() 函数,该函数可以被覆盖以控制如何处理“无法引发的异常”。 它在发生异常但 Python 无法处理时调用。 例如,当析构函数引发异常或在垃圾收集期间 (gc.collect())。 (由 Victor Stinner 在 中提供:问题:`36829`。)
tar文件
tarfile 模块现在默认为新存档的现代 pax (POSIX.1-2001) 格式,而不是以前的 GNU 特定格式。 这通过标准化和可扩展格式的一致编码 (UTF-8) 提高了跨平台可移植性,并提供了其他一些好处。 (由 CAM 提供 中的 Gerlach:问题:`36268`。)
穿线
添加一个新的 threading.excepthook() 函数来处理未捕获的 threading.Thread.run() 异常。 它可以被覆盖以控制如何处理未捕获的 threading.Thread.run() 异常。 (由 Victor Stinner 在 中提供:问题:`1230540`。)
向 threading.Thread 类添加一个新的 threading.get_native_id() 函数和一个 native_id 属性。 它们返回内核分配的当前线程的本机完整线程 ID。 此功能仅在某些平台上可用,有关详细信息,请参阅 get_native_id。 (由 Jake Tesler 在 中提供:issue:`36084`。)
标记化
tokenize 模块现在在提供没有尾随换行符的输入时隐式发出 NEWLINE
令牌。 此行为现在与 C 标记器在内部执行的操作相匹配。 (由 Ammar Askar 在 中提供:issue:`33899`。)
特金特
在 tkinter.Spinbox
类中添加了方法 selection_from()
、selection_present()
、selection_range()
和 selection_to()
。 (由 Juliette Monsel 在 中提供:issue:`34829`。)
在 tkinter.Canvas
类中添加了方法 moveto()
。 (由 Juliette Monsel 在 中提供:issue:`23831`。)
tkinter.PhotoImage
类现在有 transparency_get()
和 transparency_set()
方法。 (由 Zackery Spytz 在 中提供:issue:`25451`。)
打字
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']: ...
“最终”变量、函数、方法和类。 参见 PEP 591、typing.Final 和 typing.final()。 最后的限定符指示静态类型检查器限制子类化、覆盖或重新分配:
pi: Final[float] = 3.1415926536
协议定义。 参见 PEP 544、typing.Protocol 和 typing.runtime_checkable()。 像 typing.SupportsInt 这样的简单 ABC 现在是
Protocol
子类。新协议类 typing.SupportsIndex。
单码数据
unicodedata 模块已升级为使用 Unicode 12.1.0 版本。
新函数 is_normalized() 可用于验证字符串是否为特定的范式,通常比实际对字符串进行规范化要快得多。 (由 Max Belanger、David Euresti 和 Greg Price 在 :issue:`32285` 和 :issue:`37966` 中提供)。
单元测试
添加了 AsyncMock 以支持 Mock 的异步版本。 还添加了用于测试的适当的新断言函数。 (由 Lisa Roach 在 :issue:`26467` 中提供)。
将 addModuleCleanup() 和 addClassCleanup() 添加到单元测试以支持对 setUpModule()
和 setUpClass() 的清理。 (由 Lisa Roach 在 中提供:问题:`24412`。)
几个模拟断言函数现在还会在失败时打印实际调用列表。 (由 Petter Strandmark 在 中提供:问题:`35047`。)
unittest 模块通过 unittest.IsolatedAsyncioTestCase 获得了对协程用作测试用例的支持。 (由 Andrew Svetlov 在 中提供:issue:`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 在 中贡献:问题:`32718`。)
xml
作为对 DTD 和外部实体检索的缓解,xml.dom.minidom 和 xml.sax 模块默认不再处理外部实体。 (由 Christian Heimes 在 中提供:issue:`17239`。)
xml.etree.ElementTree 模块中的 .find*()
方法支持通配符搜索,例如忽略命名空间的 {*}tag
和返回给定中的所有标签的 {namespace}*
命名空间。 (由 Stefan Behnel 在 中提供:issue:`28238`。)
xml.etree.ElementTree 模块提供了一个实现 C14N 2.0 的新函数 –xml.etree.ElementTree.canonicalize()
。 (由 Stefan Behnel 在 中提供:issue:`13611`。)
xml.etree.ElementTree.XMLParser的目标对象可以通过新的回调方法start_ns()
和end_ns()
接收命名空间声明事件。 此外,xml.etree.ElementTree.TreeBuilder 目标可以配置为处理关于评论和处理指令的事件,以将它们包含在生成的树中。 (由 Stefan Behnel 在 :issue:`36676` 和 :issue:`36673` 中贡献。)
xmlrpc
xmlrpc.client.ServerProxy 现在支持可选的 headers 关键字参数,用于与每个请求一起发送的 HTTP 标头序列。 除此之外,这使得从默认的基本身份验证升级到更快的会话身份验证成为可能。 (由 Cédric Krier 在 中提供:issue:`35153`。)
优化
subprocess 模块现在可以在某些情况下使用 os.posix_spawn() 函数以获得更好的性能。 目前,如果满足所有这些条件,它仅用于 macOS 和 Linux(使用 glibc 2.24 或更新版本):
close_fds 为假;
preexec_fn、pass_fds、cwd和start_new_session参数未设置;
executable 路径包含一个目录。
(由 Joannah Nanjekye 和 Victor Stinner 在 中提供:issue:`35537`。)
shutil.copyfile()、shutil.copy()、shutil.copy2()、shutil.copytree()和 ]shutil.move() 在 Linux 和 macOS 上使用特定于平台的“快速复制”系统调用,以便更有效地复制文件。 “快速复制”意味着复制操作发生在内核中,避免在 Python 中使用用户空间缓冲区,如“
outfd.write(infd.read())
”。 在 Windows 上 shutil.copyfile() 使用更大的默认缓冲区大小(1 MiB 而不是 16 KiB)和基于 memoryview() 的 shutil.copyfileobj() 变体使用 。 在同一分区内复制 512 MiB 文件的加速约为 +26% on Linux、+50% on macOS 和 +40% on Windows。 此外,消耗的 CPU 周期要少得多。 请参阅 依赖于平台的高效复制操作 部分。 (由 Giampaolo Rodolà 在 中提供:issue:`33671`。)shutil.copytree() 使用 os.scandir() 函数和所有依赖于它的复制函数使用缓存的 os.stat() 值。 复制包含 8000 个文件的目录的加速约为 +9% on Linux、+20% on Windows 和 +30% on Windows SMB 共享。 os.stat() 系统调用的数量也减少了 38%,使得 shutil.copytree() 在网络文件系统上特别快。 (由 Giampaolo Rodolà 在 中提供:issue:`33695`。)
pickle 模块中的默认协议现在是协议 4,首先在 Python 3.4 中引入。 与自 Python 3.0 以来可用的协议 3 相比,它提供了更好的性能和更小的尺寸。
从
PyGC_Head
中移除了一个Py_ssize_t
成员。 所有 GC 跟踪的对象(例如 元组、列表、字典)大小减少 4 或 8 个字节。 (由 Inada Naoki 在 中提供:issue:`33597`。)uuid.UUID 现在使用
__slots__
来减少其内存占用。 (由 Wouter Bolsterlee 和 Tal Einat 在 中提供:issue:`30977`)operator.itemgetter() 的性能提高了 33%。 优化参数处理并为单个非负整数索引的常见情况添加到元组中的快速路径(这是标准库中的典型用例)。 (由 Raymond Hettinger 在 中提供:issue:`35664`。)
collections.namedtuple() 中的加速字段查找。 它们现在的速度提高了两倍多,使它们成为 Python 中最快的实例变量查找形式。 (由 Raymond Hettinger、Pablo Galindo 和 Joe Jevnik、Serhiy Storchaka 在 :issue:`32492` 中提供。)
如果输入可迭代对象的长度已知(输入实现
__len__
),则 list 构造函数不会过度分配内部项目缓冲区。 这使得创建的列表平均小 12% s。 (由 Raymond Hettinger 和 Pablo Galindo 在 中提供:issue:`33234`。)将类变量写入的速度加倍。 更新非 dunder 属性时,会不必要地调用更新槽。 (由 Stefan Behnel、Pablo Galindo Salgado、Raymond Hettinger、Neil Schemenauer 和 Serhiy Storchaka 在 :issue:`36012` 中提供。)
减少了转换传递给许多内置函数和方法的参数的开销。 这将调用一些简单的内置函数和方法的速度加快了 20-50%。 (由 Serhiy Storchaka 在 :issue:`23867`、:issue:`35582` 和 :issue:`36127` 中贡献。)
LOAD_GLOBAL
指令现在使用新的“每个操作码缓存”机制。 现在大约是 40% faster。 (由 Yury Selivanov 和 Inada Naoki 在 中提供:issue:`26219`。)
构建和 C API 更改
默认 sys.abiflags 变为空字符串:pymalloc 的
m
标志变得无用(使用和不使用 pymalloc 的构建都与 ABI 兼容),因此已被删除。 (由 Victor Stinner 在 中提供:问题:`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 在 :issue:`35134` 和 :issue:`35081` 中贡献,Eric Snow 在 Python 3.7 中发起的工作。)
一些宏已转换为静态内联函数:参数类型和返回类型定义良好,它们没有特定于宏的问题,变量具有局部作用域。 例子:
PyObject_INIT()
、PyObject_INIT_VAR()
私有功能:
_PyObject_GC_TRACK()
、_PyObject_GC_UNTRACK()
、_Py_Dealloc()
(由 Victor Stinner 在 中提供:问题:`35059`。)
PyByteArray_Init()
和PyByteArray_Fini()
功能已被删除。 自 Python 2.7.4 和 Python 3.2.0 以来,他们什么也没做,被排除在有限的 API(稳定 ABI)之外,并且没有记录。 (由 Victor Stinner 在 中提供:问题:`35713`。)PyExceptionClass_Name()
的结果现在是const char *
类型而不是char *
。 (由 Serhiy Storchaka 在 中提供:issue:`33818`。)Modules/Setup.dist
和Modules/Setup
的二元性已被移除。 以前,在更新 CPython 源代码树时,必须手动将Modules/Setup.dist
(源代码树内部)复制到Modules/Setup
(构建树内部),以反映上游的任何更改。 这对打包人员来说是一个小好处,但代价是在 CPython 开发之后经常给开发人员带来烦恼,因为忘记复制文件可能会导致构建失败。现在构建系统总是从源代码树中的
Modules/Setup
读取。 鼓励想要自定义该文件的人在 CPython 的 git fork 或补丁文件中维护他们的更改,就像他们对源树的任何其他更改所做的一样。(由 Antoine Pitrou 在 中提供:issue:`32430`。)
将 Python 数字转换为 C 整数的函数(如 PyLong_AsLong())和参数解析函数(如 PyArg_ParseTuple() 与整数转换格式单位(如
'i'
)现在将使用 ]__index__() 特殊方法而不是 __int__()(如果可用)。 对于具有__int__()
方法但没有__index__()
方法的对象(如 Decimal 和 Fraction),将发出弃用警告。 PyNumber_Check() 现在将为实现__index__()
的对象返回1
。 PyNumber_Long()、PyNumber_Float() 和 PyFloat_AsDouble() 现在也使用__index__()
方法(如果可用)。 (由 Serhiy Storchaka 在 :issue:`36048` 和 :issue:`20092` 中贡献。)堆分配的类型对象现在将在 PyObject_Init()(及其并行宏
PyObject_INIT
)中增加它们的引用计数,而不是在 PyType_GenericAlloc() 中。 可能需要调整修改实例分配或释放的类型。 (由 Eddie Elizondo 在 中提供:issue:`35810`。)新函数 PyCode_NewWithPosOnlyArgs() 允许创建类似 PyCode_New() 的代码对象,但有一个额外的 posonlyargcount 参数用于指示仅位置参数的数量。 (由 Pablo Galindo 在 中提供:issue:`37221`。)
Py_SetPath() 现在将 sys.executable 设置为程序完整路径 (Py_GetProgramFullPath()) 而不是程序名称 (Py_GetProgramName()[ X171X])。 (由 Victor Stinner 在 中提供:问题:`38234`。)
已弃用
distutils
bdist_wininst
命令现已弃用,请改用bdist_wheel
(车轮包)。 (由 Victor Stinner 在 中提供:问题:`37481`。)ElementTree 模块中已弃用的方法
getchildren()
和getiterator()
现在发出 DeprecationWarning 而不是 PendingDeprecationWarning。 它们将在 Python 3.9 中删除。 (由 Serhiy Storchaka 在 中提供:issue:`29209`。)将不是 concurrent.futures.ThreadPoolExecutor 实例的对象传递给 loop.set_default_executor() 已被弃用,并将在 Python 3.9 中被禁止。 (由 Elvis Pranskevichus 在 中提供:issue:`34075`。)
xml.dom.pulldom.DOMEventStream、wsgiref.util.FileWrapper 和 fileinput.FileInput 的
__getitem__()
方法已被弃用。这些方法的实现一直忽略它们的 index 参数,而是返回下一个项目。 (由 Berker Peksag 在 中提供:issue:`9372`。)
typing.NamedTuple 类已弃用
_field_types
属性,取而代之的是具有相同信息的__annotations__
属性。 (由 Raymond Hettinger 在 中提供:issue:`36320`。)ast 类
Num
、Str
、Bytes
、NameConstant
和Ellipsis
被视为已弃用,将在未来的 Python 版本。 应该使用 常量 来代替。 (由 Serhiy Storchaka 在 中提供:issue:`32892`。)ast.NodeVisitor 方法
visit_Num()
、visit_Str()
、visit_Bytes()
、visit_NameConstant()
和visit_Ellipsis()
现已弃用,不会在未来的 Python 版本中被调用。 添加visit_Constant()
方法来处理所有常量节点。 (由 Serhiy Storchaka 在 中提供:issue:`36917`。)asyncio.coroutine() decorator 已弃用,将在 3.10 版中删除。 使用 async def 代替
@asyncio.coroutine
。 (由 Andrew Svetlov 在 中提供:issue:`36921`。)在 asyncio 中,loop 参数的显式传递已被弃用,并将在 3.10 版中删除以用于以下内容:
asyncio.sleep()
、asyncio.gather()
、asyncio.shield()
、asyncio.wait_for()
、asyncio.wait()
、asyncio.as_completed()、asyncio.Task、 X272X]、asyncio.Event、asyncio.Condition、asyncio.Semaphore、asyncio.BoundedSemaphore[X394o2X] X420X]、asyncio.create_subprocess_exec()
和asyncio.create_subprocess_shell()
。将协程对象显式传递给
asyncio.wait()
已被弃用,并将在 3.11 版中删除。 (由 Yury Selivanov 在 中提供:issue:`34790`。)gettext 模块中不推荐使用以下函数和方法: lgettext()、ldgettext()、lngettext() 和 ]ldngettext()。 它们返回编码的字节,如果翻译的字符串存在编码问题,您可能会收到意外的与 Unicode 相关的异常。 在 Python 3 中使用返回 Unicode 字符串的替代方法要好得多。 这些功能已经被破坏了很长时间。
函数 bind_textdomain_codeset(),方法 output_charset() 和 set_output_charset(),以及函数 translation() 的参数 codeset 和 install() 也已弃用,因为它们仅用于
l*gettext()
功能。 (由 Serhiy Storchaka 在 中提供:issue:`33710`。)threading.Thread 的
isAlive()
方法已被弃用。 (由 Dong-hee Na 在 中提供:issue:`35283`。)许多采用整数参数的内置函数和扩展函数现在将针对 Decimals、Fractions 和任何其他只能转换为整数但有损失的对象(例如 具有 __int__() 方法但没有 __index__() 方法)。 在未来的版本中,它们将是错误的。 (由 Serhiy Storchaka 在 中提供:issue:`36048`。)
不推荐将以下参数作为关键字参数传递:
func in functools.partialmethod(), weakref.finalize(), profile.Profile.runcall(), [ X122X]、bdb.Bdb.runcall()、trace.Trace.runfunc() 和 curses.wrapper()。
unittest.TestCase.addCleanup() 中的 函数 。
concurrent.futures.ThreadPoolExecutor和concurrent.futures.ProcessPoolExecutor的submit()方法中的fn。
contextlib.ExitStack.callback()、
contextlib.AsyncExitStack.callback()
和 contextlib.AsyncExitStack.push_async_callback() 中的 callback。multiprocessing.managers.Server
和multiprocessing.managers.SharedMemoryServer
的create()
方法中的 c 和 typeid。obj 在 weakref.finalize()。
在 Python 的未来版本中,它们将是 positional-only。 (由 Serhiy Storchaka 在 中提供:issue:`36492`。)
API 和功能删除
以下功能和 API 已从 Python 3.8 中删除:
- 从 Python 3.3 开始,不推荐从 collections 导入 ABC,应从 collections.abc 导入。 能够从集合中导入在 3.8 中被标记为删除,但已延迟到 3.9。 (参见 :issue:`36952`。)
- Python 3.7 中弃用的
macpath
模块已被删除。 (由 Victor Stinner 在 中提供:问题:`35471`。) - 函数
platform.popen()
自 Python 3.3 起被弃用后已被删除:改用 os.popen()。 (由 Victor Stinner 在 中提供:问题:`35345`。) - 函数
time.clock()
已被删除,自 Python 3.3 起已被弃用:使用 time.perf_counter() 或 time.process_time() 代替,具体取决于您的要求, 具有明确定义的行为。 (由 Matthias Bussonnier 在 :issue:`36895` 中提供。) pyvenv
脚本已被删除,取而代之的是python3.8 -m venv
,以帮助消除关于pyvenv
脚本绑定到什么 Python 解释器的混淆。 (由 Brett Cannon 在 中提供:issue:`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 在 中提供:issue:`29209`。)
- 删除了 XMLParser 的
doctype()
方法。 (由 Serhiy Storchaka 在 中提供:issue:`29209`。) - “unicode_internal”编解码器被删除。 (由 Inada Naoki 在 中提供:issue:`36297`。)
- sqlite3 模块的
Cache
和Statement
对象不会暴露给用户。 (由 Aviv Palivoda 在 中提供:issue:`30262`。) - fileinput.input() 和 fileinput.FileInput() 的
bufsize
关键字参数自 Python 3.6 以来被忽略和弃用。 :issue:`36952`(由 Matthias Bussonnier 提供。) - Python 3.7 中弃用的函数
sys.set_coroutine_wrapper()
和sys.get_coroutine_wrapper()
已被删除; :issue:`36933`(由 Matthias Bussonnier 提供。)
移植到 Python 3.8
本节列出了可能需要更改您的代码的先前描述的更改和其他错误修正。
Python 行为的变化
- Yield 表达式(
yield
和yield from
子句)现在在推导式和生成器表达式中是不允许的(除了最左边的for
子句中的可迭代表达式)。 (由 Serhiy Storchaka 在 :issue:`10544` 中提供。) - 当身份检查(
is
和is not
)与某些类型的文字(例如 字符串、数字)。 这些通常可以在 CPython 中意外工作,但语言规范不保证。 该警告建议用户改用相等性测试(==
和!=
)。 (由 Serhiy Storchaka 在 中提供:issue:`34850`。) - 在某些情况下,CPython 解释器可以吞下异常。 在 Python 3.8 中,这种情况发生的情况较少。 特别是,不再忽略从类型字典中获取属性时引发的异常。 (由 Serhiy Storchaka 在 中提供:issue:`35459`。)
- 从内置类型 bool、int、float、complex 和标准库中的几个类中删除了
__str__
实现。 它们现在从 object 继承__str__()
。 因此,在这些类的子类中定义__repr__()
方法会影响它们的字符串表示。 (由 Serhiy Storchaka 在 中提供:issue:`36793`。) - 在 AIX 上,sys.platform 不再包含主要版本。 它总是
'aix'
,而不是'aix3'
..'aix7'
。 由于较旧的 Python 版本包含版本号,因此建议始终使用sys.platform.startswith('aix')
。 (由 M. 感觉在 :问题:`36588`。) - PyEval_AcquireLock() 和 PyEval_AcquireThread() 如果在解释器完成时调用,现在终止当前线程,使它们与 PyEval_RestoreThread(), , 一致() 和 PyGILState_Ensure()。 如果不需要此行为,请通过检查
_Py_IsFinalizing()
或sys.is_finalizing()
来保护呼叫。 (由 Joannah Nanjekye 在 :issue:`36475` 中提供。)
Python API 的变化
- os.getcwdb() 函数现在在 Windows 上使用 UTF-8 编码,而不是 ANSI 代码页:请参阅 PEP 529 了解基本原理。 该函数在 Windows 上不再被弃用。 (由 Victor Stinner 在 中提供:问题:`37412`。)
- subprocess.Popen 现在可以在某些情况下使用 os.posix_spawn() 以获得更好的性能。 在用于 Linux 和 QEMU 用户仿真的 Windows 子系统上,使用 os.posix_spawn() 的
Popen
构造函数不再引发诸如“缺少程序”之类的错误的异常。 相反,子进程以非零returncode
失败。 (由 Joannah Nanjekye 和 Victor Stinner 在 中提供:issue:`35537`。) - * subprocess.Popen 的 preexec_fn 参数不再与子解释器兼容。 现在在子解释器中使用参数会引发 RuntimeError。 (由 Eric Snow 在 :issue:`34651` 中贡献,由 Christian Heimes 在 :issue:`37951` 中修改。)
imap.IMAP4.logout()
方法不再默默地忽略任意异常。 (由 Victor Stinner 在 中提供:问题:`36348`。)- 函数
platform.popen()
自 Python 3.3 起被弃用后已被删除:改用 os.popen()。 (由 Victor Stinner 在 中提供:问题:`35345`。) - statistics.mode() 函数在给定多模式数据时不再引发异常。 相反,它返回输入数据中遇到的第一个模式。 (由 Raymond Hettinger 在 中提供:issue:`35892`。)
- tkinter.ttk.Treeview 类的 selection() 方法不再接受参数。 在 Python 3.6 中不推荐使用它与更改选择的参数。 使用诸如 selection_set() 之类的专门方法来更改选择。 (由 Serhiy Storchaka 在 中提供:issue:`31508`。)
writexml()
、toxml()
和toprettyxml()
方法 xml.dom.minidom 和xml.etree
方法write()
],现在保留用户指定的属性顺序。 (由 Diego Rojas 和 Raymond Hettinger 在 :issue:`34160` 中提供。)- 使用标志
'r'
打开的 dbm.dumb 数据库现在是只读的。 dbm.dumb.open() 带有标志'r'
和'w'
如果数据库不存在,则不再创建数据库。 (由 Serhiy Storchaka 在 中提供:issue:`32749`。) - 在 XMLParser 的子类中定义的
doctype()
方法将不再被调用,并将发出 RuntimeWarning 而不是 DeprecationWarning。 在目标上定义 doctype() 方法来处理 XML 文档类型声明。 (由 Serhiy Storchaka 在 中提供:issue:`29209`。) - 当自定义元类未在传递给
type.__new__
的命名空间中提供__classcell__
条目时,现在会引发 RuntimeError。 在 Python 3.6-3.7 中发出了 DeprecationWarning。 (由 Serhiy Storchaka 在 中提供:issue:`23722`。) cProfile.Profile
类现在可以用作上下文管理器。 (由 Scott Sanderson 在 中提供:issue:`29235`。)- shutil.copyfile()、shutil.copy()、shutil.copy2()、shutil.copytree()和 ]shutil.move() 使用特定于平台的“快速复制”系统调用(参见 依赖于平台的高效复制操作 部分)。
- shutil.copyfile() Windows 上的默认缓冲区大小从 16 KiB 更改为 1 MiB。
PyGC_Head
结构已经完全改变。 所有触及 struct 成员的代码都应该重写。 (参见 :issue:`33597`。)- PyInterpreterState 结构体已移入“内部”头文件(特别是 Include/internal/pycore_pystate.h)。 一个不透明的
PyInterpreterState
作为公共 API(和稳定的 ABI)的一部分仍然可用。 文档表明结构体的所有字段都不是公开的,因此我们希望没有人使用它们。 但是,如果您确实依赖于这些私有字段中的一个或多个并且别无选择,那么请打开 BPO 问题。 我们将努力帮助您进行调整(可能包括向公共 API 添加访问器功能)。 (参见 :issue:`35886`。) - mmap.flush() 方法现在在成功时返回
None
并在所有平台下引发异常。 以前,它的行为取决于平台:成功时返回一个非零值; 在 Windows 下出错时返回零。 成功时返回零值; 在 Unix 下发生错误时引发异常。 (由 Berker Peksag 在 中提供:issue:`2122`。) - xml.dom.minidom 和 xml.sax 模块默认不再处理外部实体。 (由 Christian Heimes 在 中提供:issue:`17239`。)
- 从只读 dbm 数据库(dbm.dumb、dbm.gnu 或 dbm.ndbm)中删除密钥会引发
error
(dbm.dumb.error, dbm.gnu.error 或 dbm.ndbm.error) 而不是 KeyError . (由 Zhang 在 中提供:issue:`33106`。) - 文字的简化 AST。 所有常量都将表示为 ast.Constant 实例。 实例化旧类
Num
、Str
、Bytes
、NameConstant
和Ellipsis
将返回Constant
的实例。 (由 Serhiy Storchaka 在 中提供:issue:`32892`。) - Windows 上的 expanduser() 现在更喜欢
USERPROFILE
环境变量,并且不使用HOME
,通常不会设置对于普通用户帐户。 (由 Anthony Sottile 在 中提供:issue:`36264`。) - 异常 asyncio.CancelledError 现在继承自 BaseException 而不是 Exception,并且不再继承自 concurrent.futures.CancelledError。 (由 Yury Selivanov 在 :issue:`32528` 中贡献。)
- 使用 asyncio.Task 的实例时,函数
asyncio.wait_for()
现在可以正确等待取消。 以前,在达到 timeout 时,它被取消并立即返回。 (由 Elvis Pranskevichus 在 中提供:issue:`32751`。) - 函数 asyncio.BaseTransport.get_extra_info() 现在在将 'socket' 传递给 name 参数时返回一个安全的使用套接字对象。 (由 Yury Selivanov 在 :issue:`37027` 中贡献。)
- asyncio.BufferedProtocol 已经升级到稳定的 API。
- 现在更安全地解决了 Windows 上使用 ctypes 加载的扩展模块和 DLL 的 DLL 依赖项。 仅搜索系统路径、包含 DLL 或 PYD 文件的目录以及使用 add_dll_directory() 添加的目录以查找加载时依赖项。 具体来说,不再使用
PATH
和当前工作目录,对这些进行修改将不再对正常的 DLL 分辨率产生任何影响。 如果您的应用程序依赖于这些机制,您应该检查 add_dll_directory() 并且如果它存在,在加载您的库时使用它来添加您的 DLL 目录。 请注意,Windows 7 用户需要确保已安装 Windows Update KB2533623(这也由安装程序验证)。 (由 Steve Dower 在 中提供:issue:`36085`。) - 与 pgen 相关的头文件和函数在被纯 Python 实现替换后已被删除。 (由 Pablo Galindo 在 中提供:issue:`36623`。)
- types.CodeType 在构造函数的第二个位置有一个新参数 (posonlyargcount) 以支持在 PEP 570 中定义的仅位置参数]。 第一个参数 (argcount) 现在表示位置参数的总数(包括仅位置参数)。 types.CodeType 的新
replace()
方法可用于使代码面向未来。
C API 的变化
PyCompilerFlags 结构有一个新的 cf_feature_version 字段。 它应该被初始化为
PY_MINOR_VERSION
。 默认情况下忽略该字段,并且仅当 cf_flags 中设置了PyCF_ONLY_AST
标志时才使用该字段。 (由 Guido van Rossum 在 中提供:issue:`35766`。)PyEval_ReInitThreads()
函数已从 C API 中删除。 不应显式调用它:改用 PyOS_AfterFork_Child()。 (由 Victor Stinner 在 中提供:问题:`36728`。)在 Unix 上,除 Android 和 Cygwin 外,C 扩展不再链接到 libpython。 当嵌入 Python 时,
libpython
不能用RTLD_LOCAL
加载,而是用RTLD_GLOBAL
加载。 以前,使用RTLD_LOCAL
,已经无法加载未链接到libpython
的 C 扩展,例如由*shared*
部分构建的标准库的 C 扩展。 X190X]。 (由 Victor Stinner 在 中提供:问题:`21536`。)在解析或构建值时使用
#
格式的变体(例如 PyArg_ParseTuple(), Py_BuildValue(), PyObject_CallFunction(), etc.) 没有定义PY_SSIZE_T_CLEAN
现在引发 [X1. 它将在 3.10 或 4.0 中删除。 阅读 解析参数和构建值 了解详细信息。 (由 Inada Naoki 在 中提供:issue:`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()或任何其他自定义 allocator 后发生使用 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 在 中提供:issue:`35810`。)
Py_DEPRECATED() 宏已为 MSVC 实现。 宏现在必须放在符号名称之前。
例子:
Py_DEPRECATED(3.8) PyAPI_FUNC(int) Py_OldFunction(void);
(由 Zackery Spytz 在 中提供:issue:`33407`。)
解释器不再假装支持跨功能版本的扩展类型的二进制兼容性。 第三方扩展模块导出的 PyTypeObject 应该具有当前 Python 版本中预期的所有插槽,包括 tp_finalize(不再检查 Py_TPFLAGS_HAVE_FINALIZE在阅读 tp_finalize 之前)。
(由 Antoine Pitrou 在 中提供:issue:`32388`。)
函数
PyNode_AddChild()
和PyParser_AddToken()
现在接受两个额外的int
参数 end_lineno 和 end_col_offset。允许 MinGW 工具直接链接到
python38.dll
的libpython38.a
文件不再包含在常规 Windows 发行版中。 如果你需要这个文件,它可以用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 在 中提供:issue:`37351`。)
CPython 字节码更改
通过将展开块堆栈的逻辑移动到编译器中,简化了解释器循环。 编译器现在发出显式指令,用于调整值堆栈并调用 break、continue 和 return 的清理代码。
删除操作码 :opcode:`BREAK_LOOP`、:opcode:`CONTINUE_LOOP`、:opcode:`SETUP_LOOP` 和 :opCE:`SETUP_EX 。 添加了新的操作码 :opcode:`ROT_FOUR`、:opcode:`BEGIN_FINALLY`、:opcode:`CALL_FINALLY` 和 :opcode:`POP_FINALLY `。 更改了 :opcode:`END_FINALLY` 和 :opcode:`WITH_CLEANUP_START` 的行为。
(由 Mark Shannon、Antoine Pitrou 和 Serhiy Storchaka 在 :issue:`17611` 中提供。)
添加了新的操作码 :opcode:`END_ASYNC_FOR` 用于处理在等待 async for 循环中的下一项时引发的异常。 (由 Serhiy Storchaka 在 中提供:issue:`33041`。)
:opcode:`MAP_ADD` 现在将值作为堆栈中的第一个元素,将键作为第二个元素。 正如 PEP 572 所提议的那样,进行了此更改,因此密钥始终在字典推导式中的值之前进行评估。 (由 Jörn Heissler 在 中提供:issue:`35224`。)
演示和工具
添加了一个基准脚本,用于对访问变量的各种方式进行计时:Tools/scripts/var_access_benchmark.py
。 (由 Raymond Hettinger 在 中提供:issue:`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
基准测试是在运行 macOS 64 位构建的 英特尔® 酷睿™ i7-4960HQ 处理器 上测量的,该处理器位于 python.org。 基准脚本以纳秒为单位显示计时。
Python 3.8.1 中的显着变化
由于重大的安全问题,不再支持 asyncio.loop.create_datagram_endpoint()
的 reuse_address 参数。 这是因为 UDP 中套接字选项 SO_REUSEADDR
的行为。 有关更多详细信息,请参阅 loop.create_datagram_endpoint()
的文档。 (由 Kyle Stanley、Antoine Pitrou 和 Yury Selivanov 在 :issue:`37228` 中提供。)
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 在 :issue:`42967` 中贡献。)
Python 3.8.12 中的显着变化
从 Python 3.8.12 开始,ipaddress 模块不再接受 IPv4 地址字符串中的任何前导零。 前导零是不明确的,一些库将其解释为八进制表示法。 例如,遗留函数 socket.inet_aton() 将前导零视为八进制表示法。 现代 inet_pton() 的 glibc 实现不接受任何前导零。
(最初由 Christian Heimes 在 :issue:`36384` 中贡献,并由 Achraf Merzouki 向后移植到 3.8。)