Теперь Кью работает в режиме чтения

Мы сохранили весь контент, но добавить что-то новое уже нельзя

Насколько нормально вызывать абстрактный метод из конструктора базового класса?

Хочу понять, попадает ли это под понятие «код с душко́м».
Есть базовый класс, у которого список параметров в конструкторе хочется оставить неизменным во всех подклассах, но в них нужно производить некоторую дополнительную инициализацию.
Принято решение вынести её в абстрактный метод, чтобы список параметров конструктора определялся только в одном месте в коде.
class Foo(ABC):
    def __init__(self, config: FooConfig):
        self.baz = Baz(config.baz_name)
        self.cfg = config
        self.setup()

    @abstractmethod
    def setup(self):
        """Переопределяемая часть."""

    # ...

class Bar(Foo):
    def setup(self):
        self.baz.add_something()

    # ...
Насколько я знаю, иногда вызов методов из конструктора считают дурным тоном, т.к. объект еще не создан.
Это код из микропроекта (фактически, скрипта), но было бы интересно услышать мнения в целом, когда такое использовать можно, когда лучше не надо, почему не надо и т.д.
ПрограммированиеPython
Георгий Устинов
Python Q
  · 4,8 K
старший разработчик в pseven.io  · 11 авг 2022
То, что вы сделали — это поведенческий паттерн "Шаблонный метод". Я не встречал, чтобы его называли антипаттерном, так что проблем тут не вижу. Единственное, к чему можно придраться — это вызов дополнительной логики в конструкторе. Но тут всё зависит от реализации метода setup(). По-хорошему там не должно быть сайд-эффектов типа записи в файлы/БД, а только инициализация состояния объекта.
Метод setup() у вас абстрактный, а значит программист, реализуя класс-наследник, будет обязан его реализовать. Правда в Пайтоне эта проверка будет происходить в рантайме. То есть технически можно создать класс-наследник без метода setup(), и ошибки при запуске не будет, пока дело не дойдёт до инстанцирования этого наследника. Но это проблема динамической типизации в целом, а не конкретно данного решения.
Ну и наконец, не во всех ЯП такое заработает, о чём уже сказал коллега в соседнем ответе. Например, в прототипном наследовании JavaScript на момент вызова конструктора родителя метода setup() ещё не будет. В Пайтоне же будет вызван первый метод в цепочке MRO, то есть (в данном примере) метод setup из наследника.
Что-то осталось непонятно? Спроси в нашей группе в Телеграме!Перейти на t.me/jstsmentor
1 эксперт согласен
Веб-разработчик, геймер, специалист по этике  · 19 авг 2022
У вас конструктор собирается создавать какие-то неопределённой сложности объекты самостоятельно, это воняет сильной связанностью между компонентами. def __init__(self, config: FooConfig): self.baz = Baz(config.baz_name) Я бы внедрил зависимость Baz: заставил клиентский код его создавать и снаружи в Foo передавать. Один из авторов называет сильную связанность... Читать далее
Требует осмысления. Вернусь к этому позже. Вот немного контекста. Baz - это на самом деле библиотечный класс... Читать дальше
Инженер путей сообщения – строитель  · 11 авг 2022
Тут надо прежде всего понимать, как происходит создание объектов и когда вызывается конструктор. Например в языке программирования Delphi конструктор вызывается после инициализации таблицы виртуальных методов и может содержать вызовы виртуальных (и как их подвида абстрактных методов). А вот в языке С++ конструктор вызывается до инициализации таблицы, сколько виртуальных... Читать далее
1 эксперт согласен
Хочется добавить, что использование декоратора @abstractmethod как раз позволяет не забыть переопределить метод в... Читать дальше