问题描述
我有一些辅助函数可以传递一个类型转换器和一个值。根据稍后发生的检查,我决定调用哪个辅助函数。
如何正确注释类型以缩小下面 foo
变量的类型,以便它可以通过 mypy
检查?
from typing import Type,Union
def do_something(
typ: Type[Union[float,int]],bar: Union[float,int]
) -> Union[float,int]:
return bar
foo: Type[Union[float,int,str]] = float
assert foo is float or foo is int
do_something(foo,4.4)
如果解决方案可以确保 typ
是 bar
类型的转换器,则加分!
解决方法
好吧,这里有一些有效的方法,但也许有更好的方法,无需演员表:
from typing import Type,Union,cast
def do_something(
typ: Type[Union[float,int]],bar: Union[float,int]
) -> Union[float,int]:
return bar
foo: Type[Union[float,int,str]] = float
assert foo is float or foo is int
do_something(cast(Type[float],foo),4.4)
,
您需要的工具是 TypeVar。
本质上,TypeVar 让你说“我不太清楚这是什么类型(虽然我可能有一些想法),但它在这个函数中的整个使用过程中都是一样的。” (或在某些情况下在整个类中使用)
例如,这可确保您拥有联合的每个事物在对函数的任何给定调用中都获得相同的值。
from typing import Type,TypeVar
# Define a type variable
# and list the things it is allowed to represent
NumberType = TypeVar("NumberType",float)
def do_something(
typ: Type[NumberType],bar: NumberType
) -> NumberType:
return bar
这可以合法地用 do_something(float,2.5)
调用,在这种情况下它会返回一个浮点数,或者它可以用 do_something(int,2)
调用,在这种情况下它会返回一个 int。也就是说,它确保所有的东西都匹配。
因为您将其称为类型转换器,所以我怀疑您实际上可能并不希望所有类型都匹配。如果您需要限制多个类型变量,您可以使用更像
from typing import Callable,TypeVar
# Define a type variable
# and list the things it is allowed to represent
NumberTypeIn = TypeVar("NumberTypeIn",float)
NumberTypeOut = TypeVar("NumberTypeOut",float)
def do_something(
converter: Callable[[NumberTypeIn],NumberTypeOut],bar: NumberTypeIn
) -> NumberTypeOut:
return type_(bar)
至于缩小 Type[]
的联合的原始问题,正如您所注意到的,is
不起作用。相反,您可以使用 issubclass
,如
assert not issubclass(foo,str)
或
assert issubclass(foo,int) or issubclass(foo,float)