Java et C ++ exigent qu'un constructeur de classe de base soit appelé en raison de la disposition de la mémoire.
Si vous avez une classe BaseClassavec un membre field1et que vous créez une nouvelle classe SubClassqui ajoute un membre field2, une instance de SubClasscontient un espace pour field1et field2. Vous avez besoin d'un constructeur de BaseClasspour remplir field1, sauf si vous avez besoin que toutes les classes héritées répètent BaseClassl'initialisation de leur propre constructeur. Et si field1c'est privé, alors les classes héritées ne peuvent pas s'initialiser field1.
Python n'est pas Java ou C ++. Toutes les instances de toutes les classes définies par l'utilisateur ont la même «forme». Ce sont essentiellement des dictionnaires dans lesquels des attributs peuvent être insérés. Avant qu'une initialisation n'ait été effectuée, toutes les instances de toutes les classes définies par l'utilisateur sont presque exactement les mêmes ; ce ne sont que des endroits pour stocker des attributs qui n'en stockent pas encore.
Il est donc parfaitement logique pour une sous-classe Python de ne pas appeler son constructeur de classe de base. Il pourrait simplement ajouter les attributs lui-même s'il le voulait. Il n'y a pas d'espace réservé pour un nombre donné de champs pour chaque classe dans la hiérarchie, et il n'y a aucune différence entre un attribut ajouté par code à partir d'une BaseClassméthode et un attribut ajouté par code à partir d'une SubClassméthode.
Si, comme cela est courant, vous SubClassvoulez vraiment que tous BaseClassles invariants de s soient configurés avant de procéder à sa propre personnalisation, alors oui, vous pouvez simplement appeler BaseClass.__init__()(ou utiliser super, mais c'est compliqué et a parfois ses propres problèmes). Mais vous n'êtes pas obligé. Et vous pouvez le faire avant, ou après, ou avec différents arguments. Enfer, si vous le vouliez, vous pourriez appeler le BaseClass.__init__d'une autre méthode que __init__; peut-être que vous avez une initialisation paresseuse bizarre en cours.
Python atteint cette flexibilité en gardant les choses simples. Vous initialisez les objets en écrivant une __init__méthode qui définit les attributs sur self. C'est tout. Elle se comporte exactement comme une méthode, car c'est exactement une méthode. Il n'y a pas d'autres règles étranges et peu intuitives sur les choses à faire en premier, ou les choses qui se produiront automatiquement si vous ne faites pas d'autres choses. Le seul but qu'il doit servir est d'être un hook à exécuter pendant l'initialisation de l'objet pour définir les valeurs d'attribut initiales, et c'est exactement ce qu'il fait. Si vous voulez qu'il fasse autre chose, vous l'écrivez explicitement dans votre code.
__init__méthode, et peut-être même rechercher automatiquement des sous-classes et les décorer.