问题描述
即使提供了我们期望的类型作为其参数之一,我们也可以轻松地指定函数的返回类型:
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,{'bar':1}))) # Model2(bar='1')
因此,当我调用py_model(Union [Model1,Model2],...)时,我希望它会返回Model1或Model2中的一个,因此会返回Union [Model1,Model2]
解决方法
在to
函数中使用“ Callable”代替操作符来构造类型怎么样?
然后您可以将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
上面的代码仅在i2
的mypy中引发错误