关于python的typing类型提示支持

发布于 2021-11-03  6 次阅读


前言

最近在看FATE源码时,看到函数定义中出现了这个用法,记录一下

Python 运行时不强制执行函数和变量类型注解,但这些注解可用于类型检查器、IDE、静态检查器等第三方工具。

参考文档: typing —— 类型提示支持

函数中指定参数类型

def greeting(name: str) -> str:
    return 'Hello ' + name

greeting函数中,参数name: str表示name的类型是str-> str表示返回类型也是str

类型别名

将复杂的类型用更简洁的形式表示

将类型作为常量赋给别名,就可以定义类型别名

Vector = list[float]

def scale(scalar: float, vector: Vector) -> Vector:
    return [scalar * num for num in vector]

# typechecks; a list of floats qualifies as a Vector.
new_vector = scale(2.0, [1.0, -4.2, 5.4])

在该例子中,Vector表示和list[float]相同类型,可以互换

正如前面所说,类型别名适用于简化复杂的类型签名

def test(msg: str) -> None:
    ... 

注意:None是一种类型提示特例,已被type(None)取代

NewType

使用NewType辅助类来创建不同的类型

函数原型:

def NewType(name, tp):
    """NewType creates simple unique types with almost zero
    runtime overhead. NewType(name, tp) is considered a subtype of tp
    by static type checkers. At runtime, NewType(name, tp) returns
    a dummy function that simply returns its argument. Usage::

        UserId = NewType('UserId', int)

        def name_by_id(user_id: UserId) -> str:
            ...

        UserId('user')          # Fails type check

        name_by_id(42)          # Fails type check
        name_by_id(UserId(42))  # OK

        num = UserId(5) + 1     # type: int
    """

    def new_type(x):
        return x

    new_type.__name__ = name
    new_type.__supertype__ = tp
    return new_type

注释中有这么一句话,At runtime, NewType(name, tp) returns a dummy function that simply returns its argument,类立即返回你传递给它的任何参数

from typing import NewType

UserId = NewType('UserId', int)
some_id = UserId(524313)

静态类型检查器把新类型当作原始类型的子类,适用于捕捉逻辑错误

UserId 类型的变量可执行所有 int 操作,但返回结果都是 int 类型。这种方式允许在预期 int 时传入 UserId,还能防止意外创建无效的 UserId

# 'output' is of type 'int', not 'UserId'
output = UserId(23413) + UserId(54341)

注意,这些检查只由静态类型检查器强制执行。在运行时,语句 Derived = NewType('Derived', Base) 将产生一个 Derived 类,该类立即返回你传递给它的任何参数。 这意味着语句 Derived(some_value) 不会创建一个新的类,也不会引入超出常规函数调用的很多开销。

更确切地说,在运行时,some_value is Derived(some_value) 表达式总为 True。

创建 Derived 的子类型是无效的:

from typing import NewType

UserId = NewType('UserId', int)

# Fails at runtime and does not typecheck
# 不能使用UserId作为参数创建类
class AdminUserId(UserId): pass

然而,我们可以在 "派生的" NewType 的基础上创建一个NewType

from typing import NewType

UserId = NewType('UserId', int)

ProUserId = NewType('ProUserId', UserId)

同时,ProUserId 的类型检查也可以按预期执行。


随心所至