如何定义一个字典,将类型映射到接收该类型参数的可调用对象?
在Python中,我在定义一个类型时遇到了困难。我想要一个类似这样的东西:
def foo(x: int) -> int:
return x
def bar(x: str) -> str:
return x
# [...] MyDictType would be defined here...
my_dict: MyDictType = {
int: foo, # Good
str: bar, # Good
float: bar # WRONG! Type warning!
}
MyDictType应该表示这是一个字典,它将某种类型映射到一个可以接收该类型变量的可调用对象。我在想如何使用泛型来实现这个...但我不太确定。我试过这样做:
T = TypeVar("T")
MyDictType = dict[Type[T], Callable[[T], T]]
然而,编辑器并没有显示我期待在字典第三个条目中看到的错误...
我应该如何定义MyDictType呢?
1 个回答
1
这个事情是没办法做到的。没有任何注解可以表达单个字典键和它们对应值之间的关系。
你能做到的最接近的方式是定义一个包装器:
from collections.abc import Callable
from typing import Any, TypeVar
T = TypeVar('T')
class TypeMapperThing:
_mapping: dict[type, Callable[[Any], Any]]
def __init__(self):
self._mapping = {}
def __getitem__(self, key: type[T]) -> Callable[[T], T]:
return self._mapping[key]
def __setitem__(self, key: type[T], value: Callable[[T], T]) -> None:
self._mapping[key] = value
def __delitem__(self, key: type[T]) -> None:
del self[key]
在这里,这个包装器隐藏了使用 Any
的部分,并提供了一个类型安全的外部接口。(我本可以省略 Callable
的类型参数,直接写 _mapping: dict[type, Callable]
,但那样会用到 Callable[..., Any]
,而不是 Callable[[Any], Any]
。不过这其实没什么大不了的。)
需要注意的是,没有好的方法让 __init__
接受一个字典,或者写一个接受字典的 update
方法。尝试这样做又会遇到最初的问题,就是如何为那个字典写一个类型。
我也没有使用 collections.abc.Mapping
或 collections.abc.MutableMapping
,因为这些抽象基类定义的接口也会遇到和 dict
类似的问题。