Comments 14
Может хватит уже называть def init конструктором?
А как надо назвать?
Ну может быть так как он и называется? Инициализатор?
Хоть мини статью делай про new и init и кто из них кто и что делает.
Не вижу смысла в статье - есть документация. ИМХО это вкусовщина. Если глянуть на другие языки, то init гораздо больше похож на конструктор (нет явного возвращаемого значение и есть this/self), но функционал создания объектов размазан в питоне по куче методов и не только по этим двум
По каким например? Именно же new возвращает экземпляр, почему init упорно называют конструктором некоторая часть разработчиков, если этот метод буквально навешивает (инициализирует) переменные на экземпляр класса, который уже создан и передан как первый аргумент (тот самый self - это уже готовый экземпляр) в метод?
Еще раз посмотрите на С++, Java, C#, где понятие конструктора явно существует и что он делает
Ну что вы прям переживаете, так сложилось исторически :-)
Если многие могут сразу и быстро понять про что речь, то почему бы и нет...
Здесь скорее языковой момент: мы говорим "едем на машине", однако мы ведь тоже не на крыше едем, вроде правильнее сказать "в машине" :-)
Рамальо и Лутц вас опередили, и всё уже написали. "Python, к вершинам мастерства", 779 страница. И у Лутца во 2м томе где- то.
Кстати и он и Лутц вполне называют init конструктором, хоть и оговорками. Думается, в данном случае инициализатор и конструктор могут быть синонимами.
После появления протоколов, я полностью отказался от абстрактных классов в Питоне - по-моему утиная типизация (сердце Питона) гораздо лучше ложится на протоколы
Кажется вы решаете не существующую проблему страшно сложными методами. Гораздо проще определить валидаторы отдельно и дергать их напрямую в нужных местах, а не продираться сквозь нижележащий слои абстракции, нарушая инкапсуляцию
Ну и следствие этого. Вообще наследованное самая бесполезная штука в ООП а-ля Джава - ее не было у Алана Кэя и во многих более современных языках от нее успешно отказались. Собственно ваш пример показывает почему это частенько вредная штука
С конца наверное пойду:
по п.3 не соглашусь, и даже не особо вникая в глубины программирования, можно сделать вывод: если наследование самая бесполезная штука в ООП, от нее бы отказались в принципе. Я активно использую наследование в разработке, и многие тоже. Наследование это управления повторным использованием кода.
по п.2 хм...ну мысль тоже интересная..., однако плюс реализации через ABC, в том, что она гарантирует: валидация обязательно произойдет в строго определенный момент жизненного цикла объекта. Не вижу здесь нарушение инкапсуляции. Да и если определять валидаторы отдельно, их придется дергать в каждом классе, с другой стороны зачем их дергать если есть общая логика предварительной проверки. Например, вEmailNotification вообще нет необходимости прописывать валидацию.
по п.1 Протоколы хороши для описания поведения, абстрактные классы необходимы, когда нужно передать общую реализацию или состояние. Если несколько классов не просто имеют одинаковый интерфейс, но и разделяют общую логику, ABC избавляет от дублирования.
Если я делаю большой backend я предпочитаю протоколы, с ними легче реализовать чистую архитектуру. Однако если у меня маленький сервис, типа сервиса уведомлений, где разделяется общая реализация, я бы использовал ABC, .
по п.3
"от нее бы отказались в принципе" - и от нее оказались в Go, Rust...
"управления повторным использованием кода" можно делать с помощью композиции. Я не говорю, что наследованием не надо пользоваться, если оно есть в языке, но в большинстве случаев его стоит избегать в пользу композиции в продуктовом коде, хотя в каких-то суровых библиотеках оно вполне допустимо в разумных пределах
по п.2
если вы используете протоколы и проверку типов, то вам прийдется написать соотвествующий метод. Где надо вы явно вызовите валидатор, а не будете полагаться на неявную реализацию и цепочку переопределения методов в иерархии наследованная. Явное лучше не явного. И EmailNotification вы просто его не вызовете или используете NoOps валидатор и будет понятно, что тут проверка не делается
по п.1
"абстрактные классы необходимы, когда нужно передать общую реализацию или состояние", но еще лучше композиция, разделение ответственности и отсутствие состояния. Есть валидаторы, которые только валидируют, есть сендеры, которые только посылают сообщения, есть условный мессендж процессор, которому в рамках композиции передается валидатор и сендер, а он их дергает по очереди, и не нужны никакие абстрактные классы и состояние. И уж тем более не нужны абстрактные классы в маленьких сервисах - это инструмент для больших библиотек
Но это все ИМХО - на вкус и цвет товарищей нет
Go для быстрого обмена json-ками.
Если вы пользуетесь чистой архитектурой, то валидацию вы проводите на уровне презентации, а не на уровне приложения, в то время как я использую протокол для описания интерфейсов (т.е. поведения) на уровне приложения.
В библиотеках да, но в таких сервисах тоже да (ИМХО). Если у меня количество каналов уведомлений может расширятся, думаю ABC вполне уместен, с ним как бы даже попроще будет чем с композицией.
Полезная и понятная статья, спасибо
Протокол всё же как-то более питонячий подход, чем абстрактный класс.
Пихать в абстрактный класс проверку выглядит контр-интуитивно.
Связывание абстрактных классов со свойствами в python