为类似强制转换的函数键入提示,如果无法强制转换,则会引发该函数

问题描述 投票:0回答:2

我有一个函数

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 类型解决我的问题?

python casting mypy python-typing
2个回答
4
投票

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]"

typing.cast

类型注释实际上并没有对联合类型做任何有意义的事情

@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]"

1
投票

我有同样的问题,显然目前无法表达这一点:https://github.com/python/mypy/issues/13498
但有一些工作正在允许这样做:https://github.com/python/mypy/issues/9773

现在,我在传递类型联合时所做的相当于此操作:

casted: str | int = safe_cast(cast(type, str | int), string)

因为我知道使用类型联合将适用于我的代码

© www.soinside.com 2019 - 2024. All rights reserved.