Абстрактные методы в Python

Мне нужно что-то вроде метода abstract protected в Python (3.2):

class Abstract:
    def use_concrete_implementation(self):
        print(self._concrete_method())

    def _concrete_method(self):
        raise NotImplementedError()


class Concrete(Abstract):
    def _concrete_method(self):
        return 2 * 3

Действительно ли полезно определить "абстрактный" метод только для того, чтобы поднять NotImplementedError?

Хорошо ли использовать символ подчеркивания для абстрактных методов, который был бы protected на других языках?

Улучшен ли какой-нибудь абстрактный базовый класс (abc)?

Ответы

Ответ 1

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

Если вы действительно хотите определить абстрактный базовый класс с абстрактными методами, это можно сделать с помощью модуля abc:

from abc import ABCMeta, abstractmethod

class Abstract(metaclass=ABCMeta):
    def use_concrete_implementation(self):
        print(self._concrete_method())

    @abstractmethod
    def _concrete_method(self):
        pass

class Concrete(Abstract):
    def _concrete_method(self):
        return 2 * 3

Опять же, это не обычный способ Python делать что-то. Одна из основных целей модуля abc заключалась в том, чтобы ввести механизм перегрузки isinstance(), но isinstance() проверки обычно избегают в пользу утиного ввода. Используйте его, если вам это нужно, но не как общий шаблон для определения интерфейсов.

Ответ 2

Если вы сомневаетесь, делать то, что делает Гвидо.

Нет подчеркивания. Просто определите "абстрактный метод" как однострочный, который вызывает NotImplementedError:

class Abstract():
    def ConcreteMethod(self):
        raise NotImplementedError("error message")

Ответ 3

В принципе, пустой метод в базовом классе здесь не нужен. Просто сделайте это так:

class Abstract:
    def use_concrete_implementation(self):
        print(self._concrete_method())

class Concrete(Abstract):
    def _concrete_method(self):
        return 2 * 3

На самом деле вам обычно не нужен базовый класс в Python. Поскольку все вызовы разрешены динамически, если этот метод присутствует, он будет вызываться, если нет, будет увеличен AttributeError.

Внимание: В документации необходимо указать, что _concrete_method должен быть реализован в подклассах.