首页 > 解决方案 > Python 类型提示:函数返回类型,作为参数给出,但类型是通用别名,如 Union

问题描述

我们可以轻松地指定函数的返回类型,即使我们期望的类型作为它的参数之一提供:

from typing import TypeVar, Type, Union

T = TypeVar('T')


def to(t: Type[T], v) -> T:
    return t(v)


s: str = to(str, 1)
i: int = to(str, 1)  # Ok: Expected type 'int', got 'str' instead

但是如果我们提供 Union[str, int] 作为第一个参数,它就不起作用(看不到函数本身,我们可以用这个 Union 做一些更复杂的事情,即基于提供的 Union 构建 pydantic 模型)

G = Union[str, int]
g: G = to(G, 1) # Expected type 'Type[T]', got 'object' instead 

那么如何指定函数的返回类型应该是作为第一个参数提供的类型呢?即使我们提供的不是纯类型,如 int 或 str,还要 Union?

更新

更准确地说,有我想装饰的功能

from typing import Type, Union

from pydantic import validate_arguments, BaseModel


def py_model(t, v: dict):
    def fabric():
        def f(x):
            return x

        f.__annotations__['x'] = t
        return validate_arguments(f)

    f = fabric()
    return f(v)

class Model1(BaseModel): foo: int
class Model2(BaseModel): bar: str

print(repr(py_model(Union[Model1, Model2], {'foo':1}))) # Model1(foo=1)
print(repr(py_model(Union[Model1, Model2], {'bar':1}))) # Model2(bar='1')

所以当我调用 py_model(Union[Model1, Model2], ...) 我希望它会返回 Model1 或 Model2 之一所以 Union[Model1, Model2]

标签: pythongenericstypesmypypydantic

解决方案


to函数使用“可调用”而不是运算符来构造类型怎么样?

然后,您可以将 Union 类型的构造函数作为参数。

这种实现的一个例子是:

from typing import Any, Callable, TypeVar, Type, Union

T = TypeVar('T')
V = TypeVar('V')


def to(t: Callable[[V], T], v: V) -> T:
    return t(v)

G = Union[str, int]

def build_g(v:G) -> G:
    return v if isinstance(v, int) else str(v)


s: str = to(str, 1)
i1: int = to(int, 1)
i2: int = to(str, 1)  # Ok: Expected type 'int', got 'str' instead

g1: G = to(build_g, 1) # No error raised
g2: G = to(build_g, "2") # No error raised

上面的代码只会在 mypy 中引发错误i2


推荐阅读