Python 3.8 有什么新变化
Python 3.8 有什么新变化
编者:
Raymond Hettinger(译者:wh2099 at outlook dot com)
这篇文章介绍了 Python 3.8 相比 3.7 增加的新特性。 Python 3.8 发布于 2019 年 10 月 14 日。 更详细的信息可参阅 更新日志。
摘要 — 发布重点
新的特性
赋值表达式
新增的语法 := 可在表达式内部为变量赋值。 它被昵称为“海象运算符”因为它很像是 海象的眼睛和长牙.jpg)。
在这个示例中,赋值表达式可以避免调用 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 循环计算一个值来检测循环是否终止,而同一个值又在循环体中再次被使用的情况:
## 循环处理固定长度的数据块
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 了解详情。
(由 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 不能是关键字参数
f(10, 20, 30, 40, 50, f=60) # e 必须是关键字参数
这种标记形式的一个用例是它允许纯 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-string。 形式为 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 中贡献。)
其他语言特性修改
-
在之前版本中 continue 语句不允许在 finally 子句中使用,这是因为具体实现存在一个问题。 在 Python 3.8 中此限制已被取消。 (由 Serhiy Storchaka 在 bpo-32489 中贡献。)
-
bool, int 和 fractions.Fraction 类型现在都有一个 as_integer_ratio() 方法,与 float 和 decimal.Decimal 中的已有方法类似。 这个微小的 API 扩展使得
numerator, denominator = x.as_integer_ratio()这样的写法在多种数字类型上通用成为可能。 (由 Lisa Roach 在 bpo-33073 和 Raymond Hettinger 在 bpo-37819 中贡献。) -
int, float 和 complex 的构造器现在会使用 index() 特殊方法,如果该方法可用而对应的方法 method 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 中贡献。)
-
现在 dict 和 dictview 可以使用 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 上的终端会相应地使用此代码在交互式会话中终止脚本。 (由 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() 方法现在可返回长度为二至六个元素的元组。 之前的上限为五个。 新增的第六个可选元素是签名为
(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。 此函数可被用于执行一个 coroutine 并返回结果,同时自动管理事件循环。 例如:
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 中贡献。)
将对 Happy Eyeballs 的支持添加到 asyncio.loop.create_connection()。 要指定此行为,已增加了两个新的形参: happy_eyeballs_delay 和 interleave 。 Happy Eyeballs 算法可提升支持 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
collections.namedtuple() 的 _asdict() 方法现在将返回 dict 而不是 collections.OrderedDict。 此项更改是由于普通字典自 Python 3.7 起已保证具有确定的元素顺序。 如果还需要 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() 装饰器可使用 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 在 bpo-32380 中贡献)
gc
get_objects() 现在能接受一个可选的 generation 形参来指定一个用于获取对象的生成器。 (由 Pablo Galindo 在 bpo-36016 中贡献。)
gettext
添加了 pgettext() 及其变化形式。 (由 Franz Glasner, Éric Araujo 和 Cheryl Sabella 在 bpo-2504 中贡献。)
gzip
添加 mtime 形参到 gzip.compress() 用于可重现的输出。 (由 Guo Ci Teo 在 bpo-34898 中贡献。)
对于特定类型的无效或已损坏 gzip 文件现在将引发 BadGzipFile 而不是 OSError。 (由 Filip Gruszczyński, Michele Orrù 和 Zackery Spytz 在 bpo-6584 中贡献。)
IDLE 与 idlelib
超过 N 行(默认值为 50)的输出将被折叠为一个按钮。 N 可以在 Settings 对话框的 General 页的 PyShell 部分中进行修改。 数量较少但是超长的行可以通过在输出上右击来折叠。 被折叠的输出可通过双击按钮来展开,或是通过右击按钮来放入剪贴板或是单独的窗口。 (由 Tal Einat 在 bpo-1529353 中贡献。)
在 Run 菜单中增加了 “Run Customized” 以使用自定义设置来运行模块。 输入的任何命令行参数都会被加入 sys.argv。 它们在下次自定义运行时会再次显示在窗体中。 用户也可以禁用通常的 Shell 主模块重启。 (由 Cheryl Sabella, Terry Jan Reedy 等人在 bpo-5680 和 bpo-37627 中贡献。)
在 IDLE 编辑器窗口中增加了可选的行号。 窗口打开时默认不显示行号,除非在配置对话框的 General 选项卡中特别设置。 已打开窗口中的行号可以在 Options 菜单中显示和隐藏。 (由 Tal Einat 和 Saimadhav Heblikar 在 bpo-17535 中贡献。)
现在会使用 OS 本机编码格式在 Python 字符串和 Tcl 对象间进行转换。 这允许在 IDLE 中处理 emoji 和其他非 BMP 字符。 这些字符将可被显示或是从剪贴板复制和粘贴。 字符串从 Tcl 到 Python 的来回转换现在不会再发生失败。 (过去八年有许多人都为此付出过努力,问题最终由 Serhiy Storchaka 在 bpo-13153 中解决。)
在 3.8.1 中新增:
添加切换光标闪烁停止的选项。 (由 Zackery Spytz 在 bpo-4603 中贡献。)
Esc 键现在会关闭 IDLE 补全提示窗口。 (由 Johnny Najera 在 bpo-38944 中贡献。)
上述修改已被反向移植到 3.7 维护发行版中。
添加关键字到模块名称补全列表。 (由 Terry J. Reedy 在 bpo-37765 中贡献。)
inspect
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 在 bpo-36326 中贡献。)
io
在开发模式 (-X env) 和 调试编译版 中,io.IOBase 终结器现在会在 close() 方法失败时将异常写入日志。 发生的异常在发布编译版中会被静默地忽略。 (由 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
Added a force keyword argument to logging.basicConfig() When set to true, any existing handlers attached to the root logger are removed and closed before carrying out the configuration specified by the other arguments.
这解决了一个长期存在的问题。 当一个日志处理器或 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() 不再接受非整数类参数。 (由 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() 现在对于包含在 OS 层级无法表示的字符或字节的路径将会返回 False 而不是引发 ValueError 或其子类 UnicodeEncodeError 和 UnicodeDecodeError。 (由 Serhiy Storchaka 在 bpo-33721 中贡献。)
expanduser() 在 Windows 上现在改用 USERPROFILE 环境变量而不再使用 HOME,后者通常不会为一般用户账户设置。 (由 Anthony Sottile 在 bpo-36264 中贡献。)
isdir() 在 Windows 上将不再为不存在的目录的链接返回 True。
realpath() 在 Windows 上现在会识别重解析点,包括符号链接和目录连接。
(由 Steve Dower 在 bpo-37834 中贡献。)
pathlib
pathlib.Path methods that return a boolean result like exists(), is_dir(), is_file(), is_mount(), is_symlink(), is_block_device(), is_char_device(), is_fifo(), is_socket() now return False instead of raising ValueError or its subclass UnicodeEncodeError for paths that contain characters unrepresentable at the OS level. (Contributed by Serhiy Storchaka in bpo-33721.)
Added pathlib.Path.link_to() which creates a hard link pointing to a path. (Contributed by Joannah Nanjekye in bpo-26978) Note that link_to was deprecated in 3.10 and removed in 3.12 in favor of a hardlink_to method added in 3.10 which matches the semantics of the existing symlink_to method.
pickle
pickle 扩展子类化针对 C 优化的 Pickler 现在可通过定义特殊的 reducer_override() 方法来重载函数和类的封存逻辑。 (由 Pierre Glaser 和 Olivier Grisel 在 bpo-35900 中贡献。)
plistlib
添加了新的 plistlib.UID 并启动了对读取和写入经过 NSKeyedArchiver 编码的二进制 plists 的支持。 (由 Jon Janzen 在 bpo-26707 中贡献。)
(本文超出站点单文档体积上限,已按小节截断)
