Python 3.10.0a2 版本已经于 2020-11-04 发布,因此我们可以窥见 Python 3.10 的一些新特性。这些新特性很可能会改变未来的 Python 生态系统,使其朝着更明确,更易读的方向发展,同时保持我们熟知和喜欢的易用性。
1、类型注释的进一步扩展
3.9 版对 Python 中的类型提示和注释进行了大幅度修改和清理,类型提示这似乎是一种持续的趋势,在 3.10 中得到进一步扩展,目的很明显,是为了更好的可读性,无需看代码即可得知变量和函数返回值的类型。
延迟类型注释的执行
类型注释的运行通常被认为是在函数定义时执行,这意味着类型注释以自上而下的方式逐行进行检查。
尽管看起来合乎逻辑,但是这样做有两个问题:
- 1、引用尚未定义的类本文来源gaodai#ma#com搞@代~码^网+型的类型提示(前向引用)将不起作用,必须以字符串形式表示。也就是说:假如 int 是自定义类型,我们需要编写 “int” 而不是编写 int 。
- 2、这会减慢模块导入的速度,因为此时会执行类型提示。
因此,取而代之的是延迟类型注释,将类型注释将以字符串形式存储在__annotations__
中,如果需要这些类型注释可以在运行时通过 typing.get_type_hints()
来解析,也可以通过inspect.signature()
来立即进行解析,这样的好处是可以先执行模块导入,允许前向引用,从而减少初始化时间。
新增类型注释联合操作符
3.10 通过 “|” 作为逻辑或操作符。在注释数据类型时,我们可以使用 | 作为或。例如,我们有一个预期为 int 或 float 的变量,可以写为 int | float ,如下所示:
def f(x: int | float) -> float: return x * 3.142 f(1) # pass f(1.5) # pass f('str') # linter will show annotation error
也可以使用 typing 模块提供的关键字 Union,比如 Union[int, float]
TypeAlias 注释
回到前向引用问题,避免前向引用的常见解决方案是将它们编写为字符串。
但是,将类型写为字符串会在将这些类型分配给变量时引起问题,因为 Python 会假定我们的字符串文字类型注释只是一个字符串。
在通常使用类型注释的地方使用该类型注释变量将返回错误。例如:
MyType = "ClassName" # ClassName is our type annotation def foo() -> MyType: ...
在这里,我们试图将其 MyType 用作类型的别名 ,但是, MyType 它将被读取为字符串值,而不是类型别名。只要 ClassName 在代码的后面定义,这就是有效的。当前情况下,这将引发注释错误。
为了解决这个问题,添加了一种显式标识 MyType 为类型别名的方法 :
from typing_extensions import TypeAlias MyType: TypeAlias = "ClassName" def foo() -> MyType: ... OR MyType: TypeAlias = ClassName # if we have defined ClassName already def foo() -> MyType: ...
这里说下,为什么类型很重要,尽管这当然不是一个巨大的变动,但是看到 Python 开发人员加倍努力以增强类型功能,这真是太酷了。Python 的优势在于其易用性和缺乏陡峭的学习曲线。原因之一是不需要在我们的代码中显式定义类型。
增强类型注释看起来似乎违反直觉,但是为开发人员 提供定义类型的选项 可以极大地提高代码库的可读性和可维护性。例如,从 Python transformers 库的源代码中可以看到以下说明: