问题
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