Java та C ++ вимагають, щоб конструктор базового класу викликався через компонування пам'яті.
Якщо у вас є клас BaseClass
з членом field1
, і ви створюєте новий клас, SubClass
який додає член field2
, то екземпляр SubClass
містить простір для field1
і field2
. BaseClass
Для заповнення вам потрібен конструктор field1
, якщо вам не потрібні всі класи успадковування для повторення BaseClass
ініціалізації в їхніх власних конструкторах. А якщо field1
це приватне, то класи успадкування не можуть ініціалізуватися field1
.
Python - це не Java або C ++. Усі екземпляри всіх визначених користувачем класів мають однакову "форму". Вони в основному просто словники, в які можна вставити атрибути. Перед тим, як було зроблено будь-яку ініціалізацію, всі екземпляри всіх визначених користувачем класів майже точно однакові ; вони просто місця для зберігання атрибутів, які ще не зберігаються.
Тому для підкласу Python є ідеальним не називати його конструктор базового класу. Він може просто додати самі атрибути, якщо цього захоче. Немає місця, відведеного для заданої кількості полів для кожного класу в ієрархії, і немає різниці між атрибутом, доданим кодом від BaseClass
методу, і атрибутом, доданим кодом з SubClass
методу.
Якщо, як прийнято, SubClass
насправді хочуть створити всі BaseClass
інваріанти, перш ніж він продовжить робити власні налаштування, то так, ви можете просто зателефонувати BaseClass.__init__()
(або використовувати super
, але це складне і іноді має свої проблеми). Але не потрібно. І ви можете це робити до, або після, або з різними аргументами. Пекло, якби ти хотів, ти можеш зателефонувати BaseClass.__init__
з іншого методу цілком, ніж __init__
; можливо, у вас відбувається якась химерна лінива ініціалізація.
Python досягає цієї гнучкості шляхом простоти речей. Ви ініціалізуєте об'єкти, записавши __init__
метод, який встановлює атрибути self
. Це воно. Він поводиться точно як метод, тому що це саме метод. Немає інших дивних і неінтуїтивних правил щодо речей, які потрібно зробити спочатку, або речей, які автоматично відбудуться, якщо ви не зробите інших речей. Єдина мета, якій вона повинна служити, - це гак для виконання під час ініціалізації об'єкта для встановлення початкових значень атрибутів, і він робить саме це. Якщо ви хочете, щоб це робило щось інше, ви явно записуєте це у свій код.
__init__
методу і навіть, можливо, автоматично шукати підкласи та прикрашати їх.