用户定义的泛型类型和collections.abc

时间:2015-10-14 07:33:54

标签: python python-3.x generics type-hinting

我有一个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声明自定义泛型类型的首选方法是什么?

2 个答案:

答案 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]):
    ...