Python Dictionary with generic keys and Callable[T] values

独自空忆成欢 提交于 2021-02-10 12:42:54

问题


I have some named tuples:

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

I also have functions to handle each type of tuple with:

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

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

What I want to do is create a dictionary handleTuple so I can call it like so:

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

What I cannot figure out is how to define said dictionary. I tried defining a generic T:

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

However I get an error saying "Type variable T is unbound" which I do not understand. The closest I have got so far is:

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

This works fine for calling it the way I want, however I cannot figure out the Callable part in the definition so I can include my functions. How can I do this


回答1:


TypeVars are only meaningful in aliases, classes and functions. One can define a Protocol for the lookup:

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

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

handleTuple: Handler = {JOIN: handleJoin, EXIT: handleExit}

The special method self.__getitem__(item) corresponds to self[item]. Thus, the protocol defines that accessing handleTuple[item] with item: T evaluates to some Callable[[T], bool]. Type checkers such as MyPy understand that the dict is a valid implementation of this protocol.


Since the code effectively implements a single dispatch, defining a functools.singledispatch function provides the behaviour out of the box:

@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)


来源:https://stackoverflow.com/questions/65107269/python-dictionary-with-generic-keys-and-callablet-values

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!