Python类型暗示:函数返回类型,作为参数提供,但类型是通用别名,如Union

Python类型暗示:函数返回类型,作为参数提供,但类型是通用别名,如Union,python,generics,types,mypy,pydantic,Python,Generics,Types,Mypy,Pydantic,我们可以很容易地指定函数的返回类型,即使我们期望的类型作为它的参数之一提供: 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

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

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模型)

那么,如何指定函数的返回类型应该是作为第一个参数提供的类型呢?即使我们提供的不是像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_模型(Union[Model1,Model2],…)时,我希望它将返回Model1或Model2中的一个,因此Union[Model1,Model2]

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

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

这种实施的一个例子是:

输入import Any、Callable、TypeVar、Type、Union
T=TypeVar('T')
V=TypeVar('V')
def to(t:Callable[[V],t],V:V)->t:
返回t(v)
G=联合[str,int]
def build_g(v:g)->g:
如果isinstance(v,int)或else str(v),则返回v
s:str=to(str,1)
i1:int=to(int,1)
i2:int=to(str,1)#确定:应为“int”类型,改为“str”
g1:G=to(build_G,1)#未引发错误
g2:G=to(build_G,“2”)#未引发错误

上面的代码只会在mypy中为
i2

Yes引发一个错误,因为
G
不是一个类型。您希望联合[str,in](1)如何工作?很明显,G是泛型别名,所以我想用一些魔术来提供泛型别名,并使函数返回一些与此别名对应的实例。i、 e.Union[Model1,Model2],f将根据提供的值构造Model1或Model2中的一个,因此我想指定函数的返回类型也是Union[Model1,Model2],这没有魔力。您必须使用所需的逻辑编写一个实际执行该操作的函数function@AntonOvsyannikovJuanpa所说的是构造泛型类型的函数,而不是使用
的函数。我已经发布了一个答案,可能会回答你的需要。工作,但实际上有点棘手。非常奇怪的是,泛型别名与类型相差如此之大,它们应该可以互换用作注释,所以应该有一些通用协议。
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')