# Polymorphisme: synthèse ## Polymorphisme * Le mot « polymorphisme » vient du grec et signifie « qui peut prendre plusieurs formes » * En POO, signifie que le même nom d'opérateur, de fonction ou de méthode peut être utilisé pour différents types d'arguments * En Python, on distingue le polymorphisme ad hoc, et le polymorphisme par héritage. --- ### 1. Le polymorphisme ad hoc : * Des objets de classes différentes et indépendantes, mais qui implémentent la même interface publique (même méthodes et attributs publics) sont interchangeables #### 1.1 Polymorphisme ad hoc d'opérateurs = *operator overloading* - Overloading = Surcharge - En Python, seulement grâce aux méthodes magiques ```python class MyTime: # Previously defined methods here... def __add__(self, other): secs = self.to_seconds() + other.to_seconds() return MyTime(0, 0, secs) def __eq__(self, other): if type(other) is MyTime: return self.to_seconds() == other.to_seconds() else: return False t1 = MyTime(1, 15, 42) t2 = MyTime(3, 50, 30) t3 = t1 + t2 print(t3) # Affiche 05:06:12 print(t1 == t2) # Affiche False ```` #### 1.2 Polymorphisme ad hoc de fonctions C'est le cas de nombreuses fonctions "built-in" telles que `len` ou `print`. ```python print(len("Programiz")) print(len(["Python", "Java", "C"])) print(len({"Name": "John", "Address": "Nepal"})) ``` #### 1.3 Polymorphisme ad hoc de méthodes - Grace au __typage dynamique__ de Python ou __typage canard__ ("Duck Typing") - La sémantique d’un objet est déterminée par l'ensemble de ses méthodes et ses attributs, et non par un type défini et nommé explicitement par le programmeur - *“If it walks like a duck and it quacks like a duck, then it must be a duck”* - C'est une spécificité de Python que d'autres languages, tels que Java, ne possèdent pas, i.e. on parle de *typage statique*. ```python class Duck : def __init__(self,nom): self.nom = nom def talk(self): return "Quack, quack!" def fly(self): return "Flap, flap!" def __str__(self): return self.talk() + " " + self.fly() # ------------ class Person : def __init__(self,nom) : self.nom = nom def talk(self) : return "I won the elections." def fly(self) : return "I'm flying." def __str__(self): return "I'm " + self.nom + ". " + self.talk() + " " + self.fly() # ------------ class Interview : def __init__(self,thing): self.t = thing def __str__(self): return self.t.nom + ': "' + str(self.t) + '"' ``` ```python donald = Duck("Donald Duck") interview = Interview(donald) print(interview) # Donald Duck: "Quack, quack! Flap flap! donald = Person("Donald Trump") interview = Interview(donald) print(interview) # Donald Trump: "I'm Donald Trump. I won the elections. I'm flying." ``` :::info __NB__: *Method overloading*, a way to create multiple methods in the same class with the same name but different arguments, is not possible in Python. ```python= class A: def stackoverflow(self, i='some_default_value'): print 'only method' ob=A() ob.stackoverflow(2) ob.stackoverflow() ``` You can't have two methods with the same name in Python -- and you don't need to. ::: ### 2. Le polymorphisme par héritage => *overriding* * Overriding = Redéfinition * Grâce à l'overriding, il est possible de redéfinir, dans une classe-fille, les méthodes héritées d'une classe-mère. * A chaque endroit où un objet de la classe mère est attendu, on peut utiliser un objet d’une de ces classes filles (interchangeabilité). ```python class Parent(object): def __init__(self): self.value = 5 def get_value(self): return self.value class Child(Parent): # get_value is overriden def get_value(self): return self.value + 1 ``` ### 3. La liaison dynamique - Liaision dynamique = "délégation" - C'est le fait qu'un nom de fonction membre d'une classe-mère peut être associé à une fonction membre d'une classe-fille. - Mécanisme distinct (bien qu'étroitement lié) de l'héritage. - C'est une forme de polymorphisme : grâce à la liaison dynamique, un même nom de fonction pourra correspondre à des réalisations différentes suivant les classes dérivées. | | | | ---- | ---- | | ![](https://i.imgur.com/hEyXgIF.png) | ![](https://i.imgur.com/YKWZTBf.png) | ### 4. NB: Ecrasement vs Redéfinition ;-) * Override => Redéfinition * On tire profit de l’héritage, on étend la méthode de la classe-mère (appel à `super()`) __ET__ on garde la même signature * Overwrite => Ecrasement * On ne tire pas profit de l’héritage ou; * On n'a pas exactement la même signature (mêmes paramètres). * La redéfinition réutilisera l'ancienne méthode, tandis que l'écrasement la remplace par une implémentation complètement nouvelle. ### Sources * https://www.programiz.com/python-programming/polymorphism