我如何让 mypy 识别函数的参数需要是特定基数 class 的子 class?

How do I get mypy to recognize that an argument of a function needs to be a subclass of a particular base class?

如何让 mypy 识别函数的参数需要是特定基 class 的子class?考虑以下因素:

# main.py
class A: ... 

class B(A):
  def f(self, x):
    print(x)

class C(A):
  def f(self, x):
    print(x, "in C")
# test.py
def call_f(instance):
  instance.f("Hello")

if __name__=="__main__":
  from main import B, C
  b = B()
  call_f(b)
  c = C()
  call_f(c)

main.py 所示,A 的所有子 class 实现方法 ftest.py 中的 call_f 获取 A 的子 class 之一的实例并调用此方法。 test.py.

if __name__ == "__main__": 部分显示了这方面的示例

test.py 中键入提示定义的一种方法如下:

# test_typed.py
from typing import Union
from main import B, C

def call_f(instance: Union[B, C]) -> None:
  instance.f("Hello")

if __name__=="__main__":
  from main import B, C
  b = B()
  call_f(b)
  c = C()
  call_f(c)

然而,这里的缺点是我必须不断将A的每个新子class添加到call_f的函数注释中,这似乎是重复的。

有更好的方法吗?

我想现在尝试一下答案并不是个坏主意,因为我从评论中获得了足够的信息。

您需要首先强制执行 fA 的子类实现。否则,您可以实现一个不实现 f 的子类,并且静态类型检查会(正确地)指出没有什么可以阻止这种情况的发生。如果您只希望某些子类实现 f,您可以使用 Union[B, C],但您已经声明出于可扩展性原因,这是不可取的。

您应该做的是让函数接受超类 A 的实例,并在调用超类中定义的 f 时引发错误:

from abc import ABC, abstractmethod

class A(ABC):
  @abstractmethod
  def f(self, x):
    raise NotImplementedError("This method should be defined in subclasses of A.") 

class B(A):
  def f(self, x):
    print(x)

class C(A):
  def f(self, x):
    print(x, "in C")

那么,call_f() 将如下所示:

def call_f(instance: A) -> None:
  instance.f("Hello")