Python 3.6:{method} 的签名与超类型 {Class} 不兼容

Python 3.6: Signature of {method} incompatible with super type {Class}

在尝试将我的代码更新为符合 PEP-484 标准时(我正在使用 mypy 0.610),我 运行 进入以下报告:

$ mypy mymodule --strict-optional --ignore-missing-imports --disallow-untyped-calls --python-version 3.6

myfile.py:154: error: Signature of "deliver" incompatible with supertype "MyClass"

我的班级:

from abc import abstractmethod

from typing import Any


class MyClass(object):

@abstractmethod
def deliver(self, *args: Any, **kwargs: Any) -> bool:
    raise NotImplementedError

myfile.py:

class MyImplementation(MyClass):

[...]

    def deliver(self, source_path: str,
                dest_branches: list,
                commit_msg: str = None,
                exclude_files: list = None) -> bool:

        [...]

        return True

我肯定在这里做错了什么,但我不太明白是什么:)

任何指点将不胜感激。

@abstractmethod
def deliver(self, *args: Any, **kwargs: Any) -> bool:
    raise NotImplementedError

这个声明并不意味着 subclasses 可以给 deliver 他们想要的任何签名。 Subclass deliver 方法必须准备好接受 superclass deliver 方法会接受的任何参数,所以你的 subclass deliver 必须准备好接受任意位置或关键字参数:

# omitting annotations
def deliver(self, *args, **kwargs):
    ...

您的子class的deliver没有那个签名。


如果所有子 class 都应该具有您为 MyImplementation 编写的相同 deliver 签名,那么您也应该给 MyClass.deliver 相同的签名.如果你的 subclasses 将有不同的 deliver 签名,也许这个方法不应该真正在 superclass 中,或者你可能需要重新考虑你的 class层次结构,或给他们相同的签名。

也许你应该这样解决:

  1. 定义不带参数的抽象方法:

    class MyClass:
        @abstractmethod
        def deliver(self) -> bool:
            raise NotImplementedError
    
  2. 在实现中从 self:

    获取所有数据
    class MyImplementation(MyClass):
        def __init__(
                self,
                source_path: str,
                dest_branches: list,
                commit_msg: str = None,
                exclude_files: list = None
        ) -> None:
            super().__init__()
            self.source_path = source_path
            self.dest_branches = dest_branches
            self.commit_msg = commit_msg
            self.exclude_files = exclude_files
    
        def deliver(self) -> bool:
            # some logic
            if self.source_path and self.commit_msg:
                return True
            return False
    

这样您将拥有完全兼容的方法声明,并且仍然可以根据需要实现方法。

您可以使用 Callable[..., Any]type: ignore 解决问题,如下所示。

from typing import Callable

class MyClass(object):
    deliver: Callable[..., bool]
    @abstractmethod
    def deliver(self, *args, **kwargs): # type: ignore
        raise NotImplementedError