首页 > 解决方案 > mypy 抱怨扩展基类的属性类型

问题描述

我有两个基类AB它们的定义如下:

class A(object):
    def common_function(self):
        pass
class B(object):
    def __init__(self, a: A):
        self.a = a
    def another_common_function(self):
        pass

ClassA持有一些管理信息,而 classB持有一些其他信息,这些信息基于 class 中包含的信息A,因此它知道它的实例A

我还有两个派生类dAdB它们的定义如下:

class dA(A):
    def __init__(self, t: B):
        self.t = t
class dB(B):
    def __init__(self, a: dA):
        super(A, self).__init__(a)

这些类(以及其他类似设计的 ( dA1, dB1, dA2, dB2) ...)用于某些特殊操作,因此它们需要存储更多信息,例如这对类的示例中的 t ,其他类有不同的要存储的东西。

问题是,mypy 抱怨使用dB.a.t

class dB(B):
    def __init__(self, a: dA):
        super(A, self).__init__(a)
    def do(self):
        if self.a.t is None:
            print("something")

test.py:错误:“A”没有属性“t”

抱怨其实是对的。A没有属性t。我还告诉 mypy that B.ais of type A,但在这种特殊情况下,我使用dB.aas of type dA,它实际上有 at ,但我明确告诉 mypy 否则。

问题是:

  1. 这是否违反了 Liskov 原则?
  2. 如果不是 1,有没有办法告诉 mypy 在这种特殊情况下dB.a是 type dA?我需要使用 TypeVar 吗?
  3. 如果是 1,有没有办法重组类以不违反 Liskov 原则以及让类型检查器能够识别正确的类型?

我发现了问题mypy: base class has no attribute x, how to type hint in base class,但是,扩展基类的解决方案是不可行的,因为这将t在所有派生类中都可用,不仅dA(有什么味道坏的)。

标签: pythonderived-classtypecheckingmypy

解决方案


可以使用 assert来确保它self.a的类型:dA

class dB(B):
    def __init__(self, a: dA):
        super(A, self).__init__(a)
    def do(self):
        assert isinstance(self.a, dA)
        if self.a.t is None:
            print("something")

这个断言被 mypy 识别,因此self.a被称为dA之后的实例,因此具有一个属性t


推荐阅读