与Mypy一起输入字典混合类



我正在尝试编写一个小的mixin类来桥接Set和MutableMapping类型:我希望映射类型能够接收一些对象(字节),散列它们并存储它们,以便可以通过该哈希访问它们。

这是将此类与标准dict混合的工作版本:

from hashlib import blake2b
class HashingMixin:
def add(self, content):
digest = blake2b(content).hexdigest()
self[digest] = content
class HashingDict(dict, HashingMixin):
pass

但是我不知道如何添加类型注释。

从 https://github.com/python/mypy/issues/1996 来看,mixin 似乎必须abc.ABC子类并abc.abstractmethod定义它期望调用的所有方法,所以我的镜头如下:

import abc
from hashlib import blake2b
from typing import Dict
class HashingMixin(abc.ABC):
def add(self, content: bytes) -> None:
digest = blake2b(content).hexdigest()
self[digest] = content
@abc.abstractmethod
def __getitem__(self, key: str) -> bytes:
raise NotImplementedError
@abc.abstractmethod
def __setitem__(self, key: str, content: bytes) -> None:
raise NotImplementedError

class HashingDict(Dict[str, bytes], HashingMixin):
pass

然后Mypy抱怨HashingDict定义:

error: Definition of "__getitem__" in base class "dict" is incompatible with definition in base class "HashingMixin"
error: Definition of "__setitem__" in base class "dict" is incompatible with definition in base class "HashingMixin"
error: Definition of "__setitem__" in base class "MutableMapping" is incompatible with definition in base class "HashingMixin"
error: Definition of "__getitem__" in base class "Mapping" is incompatible with definition in base class "HashingMixin"

显示类型:

reveal_type(HashingMixin.__getitem__)
reveal_type(HashingDict.__getitem__)

收益 率:

error: Revealed type is 'def (coup.content.HashingMixin, builtins.str) -> builtins.bytes'
error: Revealed type is 'def (builtins.dict[_KT`1, _VT`2], _KT`1) -> _VT`2'

我不知道怎么了:(

这似乎是 mypy 中的一个错误——在 mypy 用来分析使用多重继承的类的 MRO 的代码中查看此 TODO。简而言之,mypy 错误地完成忽略了您已经使用具体值对Dict进行了参数化,而是像使用Dict一样分析代码。

我相信 https://github.com/python/mypy/issues/5973 可能是问题跟踪器中最相关的问题:根本原因是相同的。

在该错误修复之前,您可以通过向具有错误的任何行添加# type: ignore来抑制 mypy 在该行上生成的错误。因此,在您的情况下,您可以执行以下操作:

import abc
from hashlib import blake2b
from typing import Dict
class HashingMixin(abc.ABC):
def add(self, content: bytes) -> None:
digest = blake2b(content).hexdigest()
self[digest] = content
@abc.abstractmethod
def __getitem__(self, key: str) -> bytes:
raise NotImplementedError
@abc.abstractmethod
def __setitem__(self, key: str, content: bytes) -> None:
raise NotImplementedError

class HashingDict(Dict[str, bytes], HashingMixin):  # type: ignore
pass

如果您决定采用这种方法,我建议您还留下一条额外的评论,说明您为什么要抑制这些错误并使用--warn-unused-ignores标志运行 mypy。

前者是为了将来任何代码读者的利益;后者将使mypy在遇到实际上没有抑制任何错误并且可以安全地删除的# type: ignore时报告警告。

(当然,您可以随时尝试自己提供修复!

最新更新