当前位置: 首页 > 工具软件 > PEP > 使用案例 >

PEP最新提案推出,Python将上线重大更新,带来了哪些新功能?

平羽
2023-12-01

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即将上线的部分功能,未来还将会有哪些功能呢?让我们一起拭目以待吧!

【参考资料】
https://martinheinz.dev/blog/67

 类似资料: