Python 带有通用键和 Callable[T] 值的字典

Python Dictionary with generic keys and Callable[T] values

我有一些命名元组:

JOIN = NamedTuple("JOIN", [])
EXIT = NamedTuple("EXIT", [])

我也有函数来处理每种类型的元组:

def handleJoin(t: JOIN) -> bool:
    pass

def handleExit(t: EXIT) -> bool:
    pass

我想做的是创建一个字典 handleTuple 这样我就可以这样调用它:

t: Union[JOIN, EXIT] = #an instance of JOIN or EXIT
result: bool
result = handleTuple[type(t)](t)

我想不通的是如何定义所说的字典。我尝试定义一个通用的 T:

T = TypeVar("T", JOIN, EXIT)
handleTuple: Dict[T, Callable[[T], bool]

但是我收到一条错误消息“类型变量 T 未绑定”,我不明白。到目前为止我得到的最接近的是:

handleTuple: Dict[Type[Union[JOIN, EXIT]], bool]
handleTuple = {
    JOIN: True
    EXIT: False
}

这可以很好地按照我想要的方式调用它,但是我无法弄清楚定义中的 Callable 部分,因此我可以包含我的函数。我该怎么做

TypeVars 仅在别名、类 和函数中有意义。可以定义一个 Protocol for the lookup:

T = TypeVar("T", JOIN, EXIT, contravariant=True)

class Handler(Protocol):
    def __getitem__(self, item: Type[T]) -> Callable[[T], bool]:
        ...

handleTuple = cast(Handler, {JOIN: handleJoin, EXIT: handleExit})

特殊方法self.__getitem__(item)对应self[item]。因此,该协议定义了使用 item: Type[T] 访问 handleTuple[item] 的结果是某些 Callable[[T], bool]cast 当前需要类型检查器(例如 MyPy)来理解 dict 是该协议的有效实现。


由于代码有效地实现了单个分派,因此定义 functools.singledispatch function 提供开箱即用的行为:

@singledispatch
def handle(t) -> bool:
    raise NotImplementedError

@handle.register
def handleJoin(t: JOIN) -> bool:
    pass

@handle.register
def handleExit(t: EXIT) -> bool:
    pass

t: Union[JOIN, EXIT]
result: bool
result = handle(t)