用户定义的泛型类型和集合.abc

问题描述 投票:0回答:3

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

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

from collections.abc import Mapping

class MyMapping(Mapping):
    ...

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

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

python python-3.x generics type-hinting
3个回答
0
投票

[个人意见™]:我不太支持创建新的

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

0
投票

您的原始代码可以与当前版本的 python 和 mypy 配合良好,并且完全按照您想要的方式执行所有操作(包括重用

collections.abc.Mapping
中的实现)。

但是,暂时您应该删除

bound=Hashable
,因为它尚未完全支持:

from typing import TypeVar, Hashable, Mapping

K = TypeVar("K")
V = TypeVar("V")

class MyMapping(Mapping[K, V]):
    ...

0
投票

现在

typing.Mapping
已被弃用,其功能已“转移”到
collections.abc.Mapping
,这将毫无问题地工作:

from collections.abc import Mapping, Hashable
from typing import TypeVar

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

class MyMapping(Mapping[K, V]):
    ...

自 Python 3.9 以来,通过 PEP 585,这已经成为可能。

或者,如果您更喜欢 PEP 695/Python 3.12+ 语法:

from collections.abc import Mapping, Hashable

class MyMapping[K: Hashable, V](Mapping[K, V]):
    ...
© www.soinside.com 2019 - 2024. All rights reserved.