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

Mar*_*ost 11 python generics type-hinting python-3.x

我有一个Python包,它基于collections.abc(Mapping,Sequence等)提供的ABC定义了各种集合.我想利用Python 3.5中引入的类型提示功能,但我怀疑最好的方法是什么.

让我们以其中一个类为例; 到现在为止,我有类似这样的东西:

from collections.abc import Mapping

class MyMapping(Mapping):
    ...
Run Code Online (Sandbox Code Playgroud)

要将其转换为泛型类型,文档建议执行以下操作:

from typing import TypeVar, Hashable, Mapping

K = TypeVar("K", bound=Hashable)
V = TypeVar("V")

class MyMapping(Mapping[K, V]):
    ...
Run Code Online (Sandbox Code Playgroud)

但这会带来两个问题:

  • 该类丢失了collections.abc.Mapping中的所有mixin方法.我可以自己处理这个实现它们,但这首先会破坏使用ABCs的部分目的.

  • 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]):
    ...
Run Code Online (Sandbox Code Playgroud)

但这不起作用,因为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]):
    ...
Run Code Online (Sandbox Code Playgroud)

但这闻起来很腥.导入和别名是繁琐的,由此产生的类有一个曲折的MRO,ABC提供的混合方法将没有打字信息......

那么基于集合ABC声明自定义泛型类型的首选方法是什么?

JBe*_*rdo 0

[个人意见\xe2\x84\xa2]:我不太支持创建新typing功能。这些应该足够通用,不需要对代码进行任何修改。如果您的映射类非常复杂,无法用任何常见映射(例如dict)来代替,那么您最好只使用它自己:

\n\n
def foo(bar: MyMapping) -> List:\n    pass\n
Run Code Online (Sandbox Code Playgroud)\n\n

代替

\n\n
def foo(bar: Mapping[K, V]) -> List:\n    pass\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在,如果您希望用户能够使用“键入”检查您的类typing.Mapping,您只需要子类化collections.Mapping

\n\n
class MyMapping(collections.abc.Mapping):\n    ... # define required methods\n\nisinstance(MyMapping(), typing.Mapping[K, V]) # --> True\n
Run Code Online (Sandbox Code Playgroud)\n