简体   繁体   English

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

[英]Python type hinting: function return type, given as argument, but type is Generic Alias like Union

We can specify easily return type of function, even if type we expect is provided as one of it's argument:我们可以轻松指定函数的返回类型,即使我们期望的类型是作为参数之一提供的:

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

But it does not work if we provide Union[str, int] as first argument (do not see at function itself, we can do something more complex with this Union, ie construct pydantic model based on Union provided)但是如果我们提供 Union[str, int] 作为第一个参数,它就不起作用(不要看函数本身,我们可以用这个 Union 做一些更复杂的事情,即根据所提供的 Union 构建 pydantic 模型)

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

So how to specify that return type of function should be the one provided as first argument?那么如何指定函数的返回类型应该是作为第一个参数提供的类型? Even if we provide not pure type like int or str, but also Union?即使我们提供的不是像 int 或 str 这样的纯类型,也可以提供 Union?

UPDATE更新

To be more precise there is the function i'd like to decorate更准确地说,有我想装饰的功能

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')

So when I call py_model(Union[Model1, Model2], ...) I expect it will return one of Model1 or Model2 so Union[Model1, Model2]所以当我调用 py_model(Union[Model1, Model2], ...) 我希望它会返回 Model1 或 Model2 之一所以 Union[Model1, Model2]

How about using a "Callable" for the to function, instead of the operator to construct the type?如何为to函数使用“Callable”,而不是使用运算符来构造类型?

You could then have a constructor for Union type as argument.然后,您可以将 Union 类型的构造函数作为参数。

An example of such implementation would be:这种实现的一个例子是:

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

The code above only raises an error in mypy for i2上面的代码仅在 mypy 中为i2引发错误

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM