当我定义带有泛型类型参数的类型时(例如映射的键和值的
K
/V
),我似乎无法编写合适的isinstance
检查来实现__eq__
:
from collections import OrderedDict
from collections.abc import MutableMapping
K = TypeVar("K")
V = TypeVar("V")
class MyDictWrapper(MutableMapping[K, V]):
def __init__(self):
self.cache: OrderedDict[K, V] = OrderedDict()
def __eq__(self, other: object) -> bool:
if not isinstance(other, LRUCache):
return NotImplemented
return self.cache == other.cache # Pyright error: Type of "cache" is partially unknown: Type of "cache" is "OrderedDict[Unknown, Unknown]
替代方案
if not isinstance(other, LRUCache[K, V]):
也不起作用,错误为:
Second argument to "isinstance" must be a class or tuple of classes
Generic type with type arguments not allowed for instance or class
有正确的输入方法吗?
您遇到的问题源于 Python 的运行时类型检查限制,尤其是泛型。 Python 的 isinstance 函数不支持直接检查泛型类型及其参数(例如,LRUCache[K, V])。此限制是因为由于 Python 的类型擦除,泛型类型参数(在您的情况下为 K、V)不会在运行时保留。
要以与类型检查兼容的方式正确实现 __eq__ 方法,同时在运行时仍然实用,您可以使用尊重 Python 类型系统动态特性的方法组合。
您可以采取以下方法:
避免在 isinstance 中进行直接泛型类型检查:由于不能直接将 isinstance 与泛型类型一起使用,因此请检查不带泛型参数的基类。
间接确保运行时类型兼容性:使用其他运行时检查来确保对象兼容,重点关注方法所需的结构或行为,而不是精确的类型。
对静态类型检查器使用类型提示:虽然您无法在运行时强制执行泛型类型参数,但您仍然可以通过 Mypy 或 Pyright 等工具将它们用于静态类型分析。
鉴于您的代码示例,使用 LRUCache 而不是 MyDictWrapper 似乎存在错误。假设 MyDictWrapper 是正确的类名,这是 __eq__ 方法的调整版本:
从集合导入 OrderedDict 从 collections.abc 导入 MutableMapping 从输入 import TypeVar, Generic
K = TypeVar("K") V = TypeVar("V")
类 MyDictWrapper(MutableMapping, Generic[K, V]):
def __init__(self):
self.cache: OrderedDict[K, V] = OrderedDict()
def __eq__(self, other: object) -> bool:
# Check if 'other' is instance of MyDictWrapper without generic parameters
if not isinstance(other, MyDictWrapper):
return False
# Since direct comparison of generic types at runtime is not feasible,
# compare the underlying cache directly as a practical solution.
return self.cache == other.cache
def __getitem__(self, k: K) -> V:
return self.cache[k]
def __setitem__(self, k: K, v: V) -> None:
self.cache[k] = v
def __delitem__(self, k: K) -> None:
del self.cache[k]
def __iter__(self):
return iter(self.cache)
def __len__(self) -> int:
return len(self.cache)