在 __eq__() 上使用 @singledispatchmethod:“__eq__”的签名与超类型“object”不兼容

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

这是我正在尝试做的一个最小的可重现示例(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
评论之外,我还能做什么?我已阅读这个问题,但它与类型提示无关,并且唯一的答案导致相同的错误(假设我没有做任何错误的事情)。

python type-hinting mypy
1个回答
0
投票

类型检查器正在抱怨,因为

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
© www.soinside.com 2019 - 2024. All rights reserved.