mypy жалуется на тип атрибута расширенного базового класса - PullRequest
0 голосов
/ 06 июня 2019

У меня есть два базовых класса A и B, которые определены следующим образом:

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

Класс A содержит некоторую информацию управления, тогда как класс B содержит некоторую другую информацию, котораяоснован на информации, содержащейся в классе A, и, следовательно, он знает о своем экземпляре A.

Мне также необходимо получить производные классы dA и dB, которые определены следующим образом:

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, что B.a имеет тип A, но в данном конкретном случае я использую dB.a для типа dA, который на самом деле имеет значение at, но я явно сказал mypy в противном случае.

Вопросы:

  1. Это нарушение принципа Лискова?
  2. Если не 1, есть ли способ сообщить mypy, что в данном конкретном случае dB.a имеет тип dA?Нужно ли использовать TypeVar?
  3. Если 1, есть ли способ реструктурировать классы так, чтобы он не нарушал принцип Лискова, а также позволял ли средство проверки типов распознавать правильные типы?

Я нашел вопрос mypy: у базового класса нет атрибута x, как ввести подсказку в базовом классе , однако решение по расширению базового класса неосуществимо, так как это может сделать t доступно во всех производных классах, не только dA (что-то плохо пахнет).

1 Ответ

0 голосов
/ 18 июня 2019

Можно убедиться, что self.a имеет тип dA, используя assert:

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.

...