我有一个Python包,它根据 collections.abc ( Mapping , Sequence 等)提供的ABC定义了各种集合。 )。我想利用Python 3.5中引入的类型提示功能,但我对于最好的方法有疑问。
让我们以其中一个类为例;直到现在,我有一些东西 类似这样:
from collections.abc import Mapping
class MyMapping(Mapping):
...
要将此转换为通用类型,documentation建议执行以下操作:
from typing import TypeVar, Hashable, Mapping
K = TypeVar("K", bound=Hashable)
V = TypeVar("V")
class MyMapping(Mapping[K, V]):
...
但这会带来两个问题:
该类丢失了 collections.abc.Mapping 中的所有mixin方法。我可以自己处理这个问题,但这首先会破坏使用ABC的部分目的。
isinstance(MyMapping(), collections.abc.Mapping)
返回False。此外,尝试调用collections.abc.Mapping.register(MyMapping)
来解决此问题会引发 RuntimeError (“拒绝创建继承周期”)。
我解决这些问题的第一个尝试是回到扩展 collections.abc.Mapping :
from typing import TypeVar, Hashable
from collections.abc import Mapping
K = TypeVar("K", bound=Hashable)
V = TypeVar("V")
class MyMapping(Mapping[K, V]):
...
但这不起作用,因为 collections.abc.Mapping 不是泛型类型,并且不支持订阅运算符。所以我尝试了这个:
from typing import TypeVar, Hashable, Mapping
from collections.abc import Mapping as MappingABC
K = TypeVar("K", bound=Hashable)
V = TypeVar("V")
class MyMapping(MappingABC, Mapping[K, V]):
...
但这闻起来很可疑。导入和别名很麻烦,最终的类有一个曲折的MRO,ABC提供的混合方法没有输入信息...
那么基于集合ABC声明自定义泛型类型的首选方法是什么?
答案 0 :(得分:1)
[Personal Opinion™]:我不太支持创建新的typing
功能。这些应该是通用的,不需要对代码进行任何修改。如果你的映射类非常复杂,它不能被任何常见的映射替换(比如dict
),你最好只使用它自己:
def foo(bar: MyMapping) -> List:
pass
而不是
def foo(bar: Mapping[K, V]) -> List:
pass
现在,如果您希望您的用户能够输入"键入"使用typing.Mapping
检查您的课程,您只需要继承collections.Mapping
class MyMapping(collections.abc.Mapping):
... # define required methods
isinstance(MyMapping(), typing.Mapping[K, V]) # --> True
答案 1 :(得分:0)
您的原始代码适用于当前版本的python和mypy,并且可以完全按照您的需要执行所有操作(包括重用collections.abc.Mapping
中的实现)。
但是,目前您应该删除bound=Hashable
,因为它是not fully supported yet:
from typing import TypeVar, Hashable, Mapping
K = TypeVar("K")
V = TypeVar("V")
class MyMapping(Mapping[K, V]):
...