You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.
 
 
 
 
 
 

206 line
4.1 KiB

  1. Chapitre 17 - Héritage
  2. ======================
  3. Rappel - composition
  4. ---------------------
  5. Dans le chapitre 13 on a parlé de *composition* qui décrit une relation entre deux classes.
  6. Pour rappel::
  7. class Chat:
  8. def __init__(self, nom):
  9. self.nom = nom
  10. def ronronne(self):
  11. print(self.nom, 'fait: "prrrrr"')
  12. def caresse(self):
  13. self.ronronne()
  14. class Enfant:
  15. def __init__(self, prénom, chat):
  16. self.chat = chat
  17. def console(self):
  18. self.chat.caresse()
  19. Vocabulaire
  20. -----------
  21. Ici on va parler d'héritage, qui décrit une autre relation entre classes, appelée parfois un peu abusivement "partage de code".
  22. Pour indiquer qu'une classe ``B`` hérite d'une classe ``A``, on écrit ``A`` dans des parenthèses au moment de
  23. déclarer la classe ``B``::
  24. class A:
  25. ...
  26. class B(A):
  27. ...
  28. Les trois formulations suivantes sont souvent employées:
  29. * A est la classe *parente* de B.
  30. * B *hérite* de A.
  31. * B est une classe *fille* de A.
  32. Utilisation
  33. -----------
  34. Si une méthode n'est pas trouvée dans la classe courante, Python ira la
  35. chercher dans la classe parente::
  36. class A:
  37. def méthode_dans_a(self):
  38. print("dans A")
  39. class B(A):
  40. def méthode_dans_b(self):
  41. print("dans B")
  42. b = B()
  43. b.méthode_dans_b()
  44. # Affiche: 'dans B', comme d'habitude
  45. b.méthode_dans_a()
  46. # Affiche: 'dans A'
  47. Ordre de résolution
  48. --------------------
  49. S'il y a plusieurs classes parentes, Python les remonte toutes une à une.
  50. On dit aussi qu'il y a une *hiérarchie* de classes::
  51. class A:
  52. def méthode_dans_a(self):
  53. print("dans A")
  54. class B(A):
  55. def méthode_dans_b(self):
  56. print("dans B")
  57. class C(B):
  58. def méthode_dans_c(self):
  59. print("dans C")
  60. c = C()
  61. c.méthode_dans_a()
  62. # affiche: 'dans A'
  63. Avec \_\_init\_\_
  64. --------------------
  65. La résolution fonctionne pour toutes les méthodes, y compris ``__init__``::
  66. class A:
  67. def __init__(self):
  68. print("initialisation de A")
  69. class B(A):
  70. ...
  71. b = B()
  72. # affiche: "initialisation de A"
  73. Attributs
  74. ----------
  75. Même mécanisme pour les attributs::
  76. class A:
  77. def __init__(self):
  78. self.attribut_de_a = 42
  79. class B(A):
  80. ...
  81. b = B()
  82. print(b.attribut_de_a)
  83. # affiche: 42
  84. Surcharge
  85. ----------
  86. On peut aussi *surcharger* la méthode de la classe parente dans la classe fille::
  87. class A:
  88. def une_méthode(self):
  89. print("je viens de la classe A")
  90. class B(A):
  91. def une_méthode(self):
  92. print("je viens de la classe B")
  93. b = B()
  94. b.une_méthode()
  95. # affiche: "je viens de la classe B'
  96. super()
  97. -------
  98. On peut utiliser ``super()`` pour chercher *explicitement* une méthode dans la classe parente::
  99. class A:
  100. def une_méthode(self):
  101. print("je viens de la classe A")
  102. class B(A):
  103. def une_méthode(self):
  104. super().une_méthode()
  105. print("je viens de la classe B")
  106. b = B()
  107. b.une_méthode()
  108. # affiche:
  109. # je viens de la classe A
  110. # je viens de la classe B
  111. super() et \_\_init\_\_
  112. ------------------------
  113. Erreur très courante::
  114. class A:
  115. def __init__(self):
  116. self.attribut_de_a = "bonjour"
  117. class B(A):
  118. def __init__(self):
  119. self.attribut_de_b = 42
  120. b = B()
  121. print(b.attribut_de_b)
  122. # affiche: 42
  123. print(b.attribut_de_a)
  124. # erreur: AttributeError
  125. On a surchargé ``A.__init__()``, du coup l'initialisation de A n'a jamais
  126. été faite.
  127. La plupart du temps, si ``A`` et ``B`` ont de constructeurs, on appellera
  128. ``super().__init__()`` dans le constructeur de la classe fille::
  129. class A:
  130. def __init__(self):
  131. self.attribut_de_a = "bonjour"
  132. class B(A):
  133. def __init__(self):
  134. super().__init__()
  135. self.attribut_de_b = 42
  136. b = B()
  137. print(b.attribut_de_b)
  138. # affiche: 42
  139. print(b.attribut_de_a)
  140. # affiche: "bonjour"