我有一个函数
safe_cast
它将值转换为给定类型,但如果该值在运行时不符合类型则引发:
from typing import TypeVar
T = TypeVar('T')
def safe_cast(t: type[T], value: Any) -> T:
if isinstance(value, t):
return cast(T, value)
raise TypeError()
这对于原始类型非常有效。但如果我想
safe_cast
反对 UnionType,我就会遇到问题:
string = "string"
casted: str | int = safe_cast(str | int, string)
实例检查适用于联合类型。但我的解决方案不起作用,因为 mypy 给了我
error: Argument 1 to "safe_cast" has incompatible type "UnionType"; expected "Type[<nothing>]" [arg-type]
我认为
<nothing>
在这里指的是未指定的类型变量T
。我还认为显然 mypy 无法将 Union[str, int]
解析为 Type[T]
。我的问题是:我该如何解决这个问题?
我研究了为 UnionType 创建一个重载。 IIUC,为了编写重载,我需要创建一个具有可变数量参数的通用联合类型。我没能完成这件事。
这是正确的方向吗?如果是,我该如何完成?如果不是,我如何通过
safe_cast
ing Union 类型解决我的问题?
typing.cast
在类型检查实现中可能是特殊情况,因为虽然这在 mypy 中有效,
import typing as t
if t.TYPE_CHECKING:
reveal_type(t.cast(str | int, "string")) # mypy: Revealed type is "Union[builtins.str, builtins.int]"
的类型注释实际上并没有对联合类型做任何有意义的事情:
@overload
def cast(typ: Type[_T], val: Any) -> _T: ...
@overload
def cast(typ: str, val: Any) -> Any: ...
@overload
def cast(typ: object, val: Any) -> Any: ...
您真正想做的是利用类型检查器实现已经提供的魔力。通过将
typing.cast
设置为 打字 API,同时将 safe_cast
设置为 运行时实现,可以轻松完成此操作。
import typing as t
T = t.TypeVar("T")
if t.TYPE_CHECKING:
from typing import cast as safe_cast
else:
# Type annotations don't actually matter here, but
# are nice to provide for readability purposes.
def safe_cast(t: type[T], value: t.Any) -> T:
if isinstance(value, t):
return value
raise TypeError
>>> reveal_type(safe_cast(int | str, "string")) # mypy: Revealed type is "Union[builtins.int, builtins.str]"
我有同样的问题,显然目前无法表达这一点:https://github.com/python/mypy/issues/13498
但有一些工作正在允许这样做:https://github.com/python/mypy/issues/9773
现在,我在传递类型联合时所做的相当于此操作:
casted: str | int = safe_cast(cast(type, str | int), string)
因为我知道使用类型联合将适用于我的代码