Python重写dict的__hash__方法触发mypy兼容错误的解决方案
解决办法
方案1:使用组合而非继承(推荐)
直接继承dict会因为其__hash__被设为None导致mypy报错,改用组合方式,内部维护一个dict实例,自己实现必要的映射方法和__hash__,完全避开继承冲突:
from typing import Generic, Iterator, KEY, VALUE class HashableBinnerDict(Generic[KEY, VALUE]): def __init__(self, *args, **kwargs): self._data = dict[KEY, VALUE](*args, **kwargs) self._is_frozen = False # 可选:防止哈希后修改实例 def __getitem__(self, key: KEY) -> VALUE: return self._data[key] def __setitem__(self, key: KEY, value: VALUE) -> None: if self._is_frozen: raise ValueError("Cannot modify instance after hashing") self._data[key] = value def __delitem__(self, key: KEY) -> None: if self._is_frozen: raise ValueError("Cannot modify instance after hashing") del self._data[key] def __iter__(self) -> Iterator[KEY]: return iter(self._data) def __len__(self) -> int: return len(self._data) def __hash__(self) -> int: self._is_frozen = True # 哈希后标记为不可修改 return hash(frozenset(self._data.items())) # 可选:实现常用的dict方法以保持接口一致 def items(self): return self._data.items() def keys(self): return self._data.keys() def values(self): return self._data.values()
这种方式不仅解决了mypy的报错,还遵循了"组合优于继承"的设计原则,同时可以通过_is_frozen标记避免可变实例哈希后修改导致的异常行为。
方案2:继承抽象基类MutableMapping
继承collections.abc.MutableMapping而非dict,该抽象基类定义了映射类型的标准接口,且其__hash__未被设为None,因此重写__hash__不会触发mypy的override错误:
from typing import Generic, KEY, VALUE from collections.abc import MutableMapping class HashableBinnerDict(MutableMapping[KEY, VALUE], Generic[KEY, VALUE]): def __init__(self, *args, **kwargs): self._data = dict[KEY, VALUE](*args, **kwargs) self._is_frozen = False def __getitem__(self, key: KEY) -> VALUE: return self._data[key] def __setitem__(self, key: KEY, value: VALUE) -> None: if self._is_frozen: raise ValueError("Cannot modify instance after hashing") self._data[key] = value def __delitem__(self, key: KEY) -> None: if self._is_frozen: raise ValueError("Cannot modify instance after hashing") del self._data[key] def __iter__(self): return iter(self._data) def __len__(self) -> int: return len(self._data) def __hash__(self) -> int: self._is_frozen = True return hash(frozenset(self._data.items()))
MutableMapping会自动为你实现keys()、values()、items()等常用方法,只需实现5个核心方法即可,代码更简洁。
关键注意事项
可变对象实现__hash__存在风险:如果实例在哈希后被修改,其哈希值会变化,导致它在集合或字典中无法被正确查找。上述方案中加入的_is_frozen标记可以在哈希后禁止修改,避免此类问题。
内容的提问来源于stack exchange,提问作者Mattia Surricchio
相关产品推荐
相关产品推荐

