这是我正在尝试做的一个最小的可重现示例(mypy Playground):
from functools import singledispatchmethod
class C:
value: int
def __init__(self, value: int) -> None:
self.value = value
@singledispatchmethod
def __eq__(self, other: object) -> bool:
return NotImplemented
@__eq__.register
def _(self, other: C) -> bool:
return self.value == other.value
@__eq__.register
def _(self, other: D) -> bool:
return self.value == other.foo / 2
D
实际上与问题无关,但如果你需要的话,这里是:
class D:
value: int
def __init__(self, value: int) -> None:
self.value = value
@property
def foo(self) -> int:
return 42 * self.value
mypy 给我以下错误:
main.py:12: error: Signature of "__eq__" incompatible with supertype "object" [override]
main.py:12: note: Superclass:
main.py:12: note: def __eq__(self, object, /) -> bool
main.py:12: note: Subclass:
main.py:12: note: singledispatchmethod[bool]
...这根本没有意义。除了使用
type: ignore
评论之外,我还能做什么?我已阅读这个问题,但它与类型提示无关,并且唯一的答案导致相同的错误(假设我没有做任何错误的事情)。
类型检查器正在抱怨,因为
functools.singledispatchmethod
的实例实际上并不是 Callable
(它没有 __call__
方法)。您最终可以通过 descriptor 方法 __get__
通过点属性访问获得可调用对象,但是当您只是在类主体中定义 __eq__
方法时,这里没有属性访问。
“解决方案”是对类型检查器撒谎,假装
singledispatchmethod
实际上是 Callable
。以下是使其与您的示例配合使用的最小实现(请参阅 mypy-playground):
from __future__ import annotations
import typing as t
from functools import singledispatchmethod as _singledispatchmethod
if t.TYPE_CHECKING:
import collections.abc as cx
P = t.ParamSpec("P")
T = t.TypeVar("T")
class singledispatchmethod(_singledispatchmethod[T], t.Generic[P, T]):
"""
Drop-in replacement for `functools.singledispatchmethod` when all the dispatched
methods are of the same arity
"""
def __init__(self, func: cx.Callable[t.Concatenate[t.Any, P], T], /) -> None: ...
@t.type_check_only
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> T: ...
else:
singledispatchmethod: t.Final = _singledispatchmethod
>>> class C:
... value: int
...
... def __init__(self, value: int) -> None:
... self.value = value
...
... @singledispatchmethod
... def __eq__(self, other: object, /) -> bool: # OK
... return NotImplemented