Python在上线任何新功能之前,都需要由PEP,即Python增强提案(Python Enhancement Proposal)概述新功能内容。因此,了解PEP能够知道Python在未来可能会进行哪些更新。在本文中,我们将详细讨论即将推出的几项Python新功能的提案。我们将所有提案分为以下几类,分别是语法更改、类型标注、调试、生活质量、生态改善等。
第一个提案是PEP 671,它提出了后期绑定参数默认值的语法。尽管Python中的函数可以将其他函数作为参数。但是,目前无法很好的为此类参数设置默认值。通常空值或哨兵值(全局常量)用作默认值,但这样help(function)
无法在参数上使用。因此PEP 671中描述了使用=>( param=>func())
将函数指定为默认参数的新语法。
# Current solution:
_SENTINEL = object()
def func(param=_SENTINEL):
if param is _SENTINEL:
# default_param holds expected default value
param = default_param
# New solution:
def func(param=>default_param):
...
这种变化的确有效,但我们应该谨慎添加新的语法符号或是做出过多的语法更改。我们无法确定像这样的细微改进是否需要用到另一个赋值运算符。
另一个语法更改相关的提案是PEP 654,它提出将except*
作为用于引发异常组的新语法。这样做的基本原理是Python解释器一次只能传播一个异常,但有时需要在栈展开时传播多个不相关的异常。这样可能会导致asyncio带来并发错误或在执行重试逻辑时引发的多个不同异常,例如在连接到某个远程主机时出现异常。
try:
some_file_operation()
except* OSError as eg:
for e in eg.exceptions:
print(type(e).__name__)
# FileNotFoundError
# FileExistsError
# IsADirectoryError
# PermissionError
# ...
之后是PEP 673提案。这个提案不涉及typing
模块相关知识。举个例子:假设你有一个带有set_name
方法的Person类,能够返回self
,即实例Person类。若在之后使用相同的set_name
创建子类Employee
,它会返回类型实例Employee
而不是Person
类。这对如今的类型检查并不适用——在 Python 3.10 中,类型检查器将子类中的返回类型认定基类的返回类型。PEP 673能帮助类型检查器正确推断类型:
class Person:
def set_name(self, name: str) -> Self:
self.name = name
return self
该PEP将作为Python 3.11版本的新功能推出。
除此之外,PEP提出了另一个类型变化,即任意文字字符串。目前我们无法指定函数参数的类型可以是任意文字字符串(只能使用特定的文字字符串,例如Literal["foo"])
。许多人觉得这不是什么大问题,甚至会疑惑为什么有人需要指定该参数应该是string,而不是(f-string)或是其他内插字符串。事实上,这主要涉及到一个安全问题——参数是literal的话能够避免受到注入攻击,无论是SQL/命令注入还是XSS等。拥有这一功能能使sqlite
等库在不应该使用字符串插值的时候提醒用户,因此它的确有它的用处。
PEP 669提出对CPython进行监控。此提案中提到应使用CPython进行低成本监控,这在运行调试器或分析器时不会影响Python的性能。考虑到在进行基本调试时并不会有性能损失,这对Python的用户影响不大。
但这个功能在某些情况下非常有用,例如:
对于那些想要提高Python性能的人来说,这一功能非常有用,能促进调试和基准性能问题/改进的进度。
同时,PEP 678中提到属性__note__
应该添加到BaseException类中。此属性可用于保存可以作为回溯的一部分显示的附加调试信息。
try:
raise TypeError('Some error')
except Exception as e:
e.__note__ = 'Extra information'
raise
# Traceback (most recent call last):
# File "<stdin>", line 2, in <module>
# TypeError: Some error
# Extra information
如上例所示,这能够在重新引发异常时起到作用。正如PEP 669中所提到的,这对于具有重试逻辑的库同样很有用,能够为每次的失败添加额外信息。同样,测试库可以为调试错误添加更多内容,例如变量名称和值。
除了PEP 669,另一个与调试相关的是PEP 657,该提案中提到要为Python的每个字节码指令添加额外数据。这一数据能够生成更好的回溯信息。同时该提案还建议公开API,允许其他工具(例如分析器或静态分析工具)使用数据。
这一提案看似普通,但实际上是所有提案中最实用的,因为能够带来更好的回溯信息,可以极大的改进回溯的可读性以及调试体验。
PEP 680中建议Python的标准库支持解析TOML格式,而这可能会带来bootstrapping问题。除此之外,包括flake8
在内的流行工具也不支持TOML,因为在标准库中缺乏支持。因此PEP 680建议将TOML支持添加到标准库中。
在标准库中支持常见的格式是可行的,特别是那些对于Python工具和生态系统非常重要的格式。那么我们什么时候才能在标准库中支持YAML呢?
最后一个提案是PEP 661,与“哨兵价值”有关。在Python中不能创建这类价值。如前面提到的PEP 671所示,哨兵价值通常需要用到_something = object
,而PEP 661为标准库提出了标记值的具体规范:
# Old:
_sentinel = object()
# New:
from sentinels import sentinel
some_name = sentinel("some_name")
以上就是Python即将上线的部分功能,未来还将会有哪些功能呢?让我们一起拭目以待吧!