如何注释数据类以根据初始化值获得返回值?

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

我有以下(精简的)数据类:

from dataclasses import dataclass
from typing import Union, Type

class BaseType: ...
class PathType(BaseType): ...
class DataType(BaseType): ...

_FinalTypes = Union[PathType, DataType]

@dataclass
class InterfaceInfo:
    what: Type[_FinalTypes]
    name: str

    def __call__(self, *args, **kwargs) -> _FinalTypes:
        return self.what(*args, **kwargs)

print(InterfaceInfo(PathType, "path"))
print(InterfaceInfo(DataType, "path"))

但我不确定如何正确注释它。 我的目的实际上是,无论您传入

__init__
方法中的任何类型,都应该作为物化对象从
__call__
中出来。

因为我现在写的内容,类型检查器会认为可以使用 PathType 构造一个

InterfaceInfo
,并从中产生一个 DataType 对象。

如果这是一个方法,我可以使用

@overload
来输入提示,但这是一个类,所以我不知所措...... 我研究了绑定到 BaseType 的 TypeVar。但那不是同样可能吗?或者类型检查器是否足够聪明,可以知道 Type[PathType] 进来,并且 PathType 需要出来?

如何解决这个问题?

谢谢!

python python-3.x python-typing
1个回答
2
投票

在某种程度上,可以通过根据

InterfaceInfo
类型将 what 定义为 generic
 来解决这个问题。所以我想说你关于使用类型变量的想法是正确的。

假设以下具体

BaseType
子类型:

from dataclasses import dataclass


@dataclass
class BaseType:
    pass


@dataclass
class PathType(BaseType):
    path: str


@dataclass
class DataType(BaseType):
    data: bytes

我们用

BaseType
的上限定义类型变量,然后用该类型变量注释
what
以及
__call__
返回,如下所示:

# ... import BaseType, PathType, DataType

from typing import Any, Generic, TypeVar


_T = TypeVar("_T", bound=BaseType)


@dataclass
class InterfaceInfo(Generic[_T]):
    what: type[_T]
    name: str

    def __call__(self, *args: Any, **kwargs: Any) -> _T:
        return self.what(*args, **kwargs)

用途:

path_interface = InterfaceInfo(PathType, "foo")
data_interface = InterfaceInfo(DataType, "bar")

p = path_interface(path="spam/eggs")
d = data_interface(data=b"ff00")

print(p)
print(d)

# for mypy:
reveal_type(p)
reveal_type(d)

print
调用输出:

PathType(path='spam/eggs')
DataType(data=b'ff00')

mypy
输出:

note: Revealed type is "PathType"
note: Revealed type is "DataType"

我们想要和期望什么。

我首先说“在某种程度上”的原因是,

__call__
方法的签名显然只是一种廉价的解决方法。静态类型检查器无法验证我们在调用
path_interface
data_interface
时传递的参数是否与
what
的类型兼容。

我想了一会儿,但无法想出一个类型安全的解决方案来允许将

__call__
注释为通用到 that 程度。这意味着返回类型可能是安全的,但构造函数参数不安全。也许其他人知道一种方法,或者也许 Python 类型系统不适合这个。

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