Является ли хорошей практикой помещать общие методы в абстрактный класс в Python? - PullRequest
0 голосов
/ 08 ноября 2018

Я использую модуль abc для определения интерфейса, который должны поддерживать подклассы. Есть также некоторые общие методы, которые присутствуют во всех подклассах. Можно ли поместить их в абстрактный класс или они должны содержать только абстрактные методы (т. Е. Украшенные @abc.abstractmethod)?

1 Ответ

0 голосов
/ 08 ноября 2018

TL; DR; Да, для абстрактного класса нормально иметь неабстрактные методы.

Обычно то, что мы называем абстрактный класс - это просто класс, который не может быть создан.

С другой стороны, то, что мы называем интерфейсом - это класс, который имеет только объявления методов, но не имеет реализаций. В частности, это абстрактный класс, потому что он не имеет конструктора.

Конечно, в Python нет реальных интерфейсов: у каждого метода должно быть тело. Но мы можем несколько эмулировать интерфейсы через raise NotImplementedError().

В любом случае интерфейсы образуют подмножество абстрактных классов. Это, очевидно, предполагает, что существуют абстрактные классы, которые не являются интерфейсами. Это именно тот случай, который вы описываете. Да, абстрактный класс может содержать реализованные неабстрактные методы. И это неплохая практика. Это особенно полезно, когда данный метод не зависит от конкретной реализации.


Например, рассмотрим интерфейс для универсального синтаксического анализатора (я думаю о json.load и json.loads):

class ILoader(ABC):
    @abstractmethod
    def load(self, stream):
        raise NotImplementedError()

Совершенно нормально дать loads метод, который принимает строку вместо потока с реализацией по умолчанию:

class AbstractLoader(ABC):
    @abstractmethod
    def load(self, stream):
        raise NotImplementedError()

    def loads(self, text):
        stream = io.StringIO(text)
        return self.load(stream)

хотя я бы использовал префикс Abstract вместо I. ;)

...