Рассмотрим следующий набор классов:
from abc import ABC, abstractmethod
class GrandParent(ABC):
@abstractmethod
def foo(self):
raise NotImplementedError()
@abstractmethod
def bar(self):
raise NotImplementedError()
class Parent1(GrandParent):
def foo(self):
print("Parent 1")
class Parent2(GrandParent):
def foo(self):
print("Parent 2")
class Child1A(Parent1):
def bar(self):
print("Child 1A")
class Child1B(Parent1):
def bar(self):
print("Child 1B")
Здесь GrandParent,
Parent1
и Parent2
являются абстрактными классами, а единственными конкретными являются Child1A
и Child1B
. Однако pylint
жалуется на Parent
s, что:
W0223: Method 'bar' is abstract in class 'GrandParent' but is not overridden (abstract-method)
Я могу понять причину, заключающуюся в том, что, взглянув на само определение класса, нельзя понять, что он должен быть абстрактным классом. Интересно, есть ли декоратор или что-то, что мне нужно использовать, чтобы явно указать это?
Одним из очевидных способов было бы переопределить абстрактный метод bar
в Parent1
и Parent2
, но это мне не кажется разумным (что, если в GrandParent
есть 10 других абстрактных методов, которые дети должны переопределить ?, все 10 из них должны быть скопированы в Parent
s?)
Обновление
В комментариях было высказано предположение, что это поведение pylint
-specifi c, что промежуточные неявные ABC пока не поддерживаются. Чтобы избавиться от предупреждения (не отключая его), достаточно переопределить один из абстрактных методов GrandParent
в Parent1
с использованием декоратора @abstractmethod
. Действительно, это решает проблему, но вызовет проблемы в сценарии множественного наследования ios:
from abc import ABC, abstractmethod
class Base(ABC):
@abstractmethod
def foo(self):
raise NotImplementedError()
@abstractmethod
def bar(self):
raise NotImplementedError()
def baz(self):
return 'baz'
def qux(self):
return 'qux'
class C1(Base):
def qux(self):
return super().qux().upper()
# @abstractmethod
# def bar(self):
# raise NotImplementedError()
class C2(Base):
def foo(self):
return 'FOO'
def bar(self):
return 'BAR'
class D(C1, C2):
pass
Здесь C1
является промежуточным неявным AB C, поэтому pylint
предупреждает. Тем не менее, D
- это конкретный класс. Чтобы избавиться от предупреждения pylint
, мы можем раскомментировать переопределение bar
в C1
. Но тогда нельзя создать экземпляр D
--- Python жалуется, что bar
является абстрактным в C1
и не определен в D
.