Dans cet article, nous allons explorer le concept de remplacement en Python. Nous allons également explorer ce que sont les méthodes magiques et les classes abstraites.
Présentation
La surcharge est un concept intéressant dans la programmation orientée objet. Lorsque les définitions de méthode d'une classe de base sont modifiées dans une classe de sous-classe (dérivée), cela s'appelle un remplacement de méthode. Vous conservez la même signature de la méthode mais modifiez la définition ou l'implémentation d'une méthode définie par l'un des ancêtres. Il n'y a pas de syntaxe spéciale ou de mots-clés supplémentaires nécessaires pour remplacer la méthode en Python. C'est un concept de programmation orienté objet très important car il permet à l'héritage d'exploiter toute sa puissance. Essentiellement, vous ne dupliquez pas de code, suivant ainsi le principe de programmation de DRY (ne vous répétez pas), et vous pouvez améliorer la méthode dans la sous-classe.
Pour comprendre le concept de remplacement, vous devez connaître les concepts de base de la programmation orientée objet tels que les classes et l'héritage. Il existe de nombreuses ressources sur Internet concernant la POO. Une très bonne ressource est la classe Python orientée objet de Finxter Academy :https://academy.finxter.com/university/object-oriented-python/
Besoin de dérogations
Dans l'exemple suivant, vous voyez comment fonctionne l'héritage et le problème de ne pas redéfinir une méthode dans la sous-classe. La classe Parent a une méthode whoami
qui affiche “I am a parent”
. Cette méthode est héritée par le Child
classer. Appeler le whoami
de la classe Child, appelle la méthode héritée de la classe Parent et affiche donc “I am a parent”
ce qui est faux.
Exemple d'héritage sans remplacement de méthode :
class Parent(): def whoami(self): print("I am a parent") class Child(Parent): def play(self): print(" I am playing") child = Child() child.whoami() # Output: # I am a parent
Remplacement de base
L'exemple suivant montre comment fonctionne le remplacement de base. Dans cet exemple, le Child
la classe a une définition du whoami
méthode qui remplace la méthode du Parent
classer. Appeler le whoami
méthode du Child
la classe affiche maintenant “I am a child”
.
Exemple de remplacement de base :
#Overriding class Parent(): def whoami(self): print("I am a parent") class Child(Parent): def play(self): print(" I am playing") def whoami(self): print("I am a child") parent = Parent() parent.whoami() print() child = Child() child.whoami() # Output: # I am a parent # I am a child
Étendre une méthode via des remplacements
Le troisième exemple montre comment vous pouvez étendre une méthode dans une classe de base en remplaçant la méthode dans la sous-classe. Pour ce faire, nous utilisons le super()
fonction intégrée. Il renvoie un objet proxy qui nous permet d'accéder aux méthodes de la classe de base. Nous pouvons faire référence à la classe de base à partir de la sous-classe sans avoir à appeler explicitement le nom de la classe de base.
Le Employee
classe contient les détails suivants pour l'employé :numéro d'employé, nom de l'employé, salaire et numéro de service. Cette information est transmise à l'objet instancié dans le __init__
méthode. Le showEmployee
La méthode de la classe affiche alors ces informations formatées à l'aide de retours à la ligne.
Le Salesman
la classe hérite du Employee
classer. Par défaut, il hérite du showEmployee
méthode telle quelle à partir du Employee
classer. Le seul problème est que nous voulons afficher la commission que le vendeur reçoit dans le cadre des informations imprimées. C'est ici qu'il faut passer outre. Nous voulons réutiliser le showEmployee
méthode du Employee
classe mais nous voulons l'étendre pour ajouter les informations de commission. Ceci est accompli en utilisant le super()
fonction intégrée. Dans l'exemple ci-dessous, vous voyez que dans le Salesman
classe, super()
est utilisé deux fois. Le __init__
la méthode l'utilise pour appeler le __init__
méthode de la classe de base Employee et le showEmployee
l'utilise pour remplacer le showEmployee
méthode du Employee
classe de base. Dans celui-ci, nous affichons les informations sur l'employé pour le vendeur plus la commission pour le vendeur.
Une troisième classe appelée CEO
utilise la même logique que précédemment. Le showEmployee
la méthode dans ce cas affiche les informations sur l'employé ainsi que les options d'achat d'actions pour le CEO
.
class Employee(): def __init__(self, empno, ename, salary, deptno): self.Empno = empno self.Ename = ename self.Salary = salary self.Deptno = deptno def showEmployee(self): print("Employee # : {}\nEmployee Name : {}\nSalary : {}\nDepartment : {}".format(self.Empno, self.Ename, self.Salary, self.Deptno)) class Salesman(Employee): def __init__(self, empno, ename, salary, deptno, comm): self.Commission = comm super().__init__(empno, ename, salary, deptno) def showEmployee(self): print("Salesman Profile") super().showEmployee() print("Commision : ", self.Commission) class CEO(Employee): def __init__(self, empno, ename, salary, deptno, stock): self.Stock = stock super().__init__(empno, ename, salary, deptno) def showEmployee(self): print("CEO Profile") super().showEmployee() print("Stock Options : ", self.Stock) salesman = Salesman(200, "John Doe", 67000, "Sales", 100) salesman.showEmployee() print("") ceo = CEO(40, "Jennifer Smith", 300000, "Director", 1000000) ceo.showEmployee()
Sortie :
Salesman Profile Employee # : 200 Employee Name : John Doe Salary : 67000 Department : Sales Commision : 100 CEO Profile Employee # : 40 Employee Name : Jennifer Smith Salary : 300000 Department : Director Stock Options : 1000000
Suppression de l'héritage multiple
Comprendre l'héritage multiple a ses propres défis. L'un d'eux est l'utilisation de super()
. Voici un lien vers un article sur ce problème :https://www.datacamp.com/community/tutorials/super-multiple-inheritance-diamond-problem
Dans l'exemple ci-dessous, je voulais montrer un moyen de remplacer une méthode d'une sous-classe avec un héritage multiple. L'exemple se compose de trois classes :Account
, Customer
, et Orders
.
- Le
Account
classe a son nom et son numéro et une méthode d'affichage qui affiche ces informations. - Le
Customer
classe a aussi son nom et son numéro et une méthode d'affichage qui affiche ces informations. - Le
Orders
La classe affiche les informations sur les commandes d'un client dans un compte spécifique. Il hérite à la fois duAccount
et la classe Commandes. La méthode d'affichage de cette classe remplace les méthodes d'affichage des classes de base. La méthode d'affichage imprime les informations sur le compte, les informations sur le client et les informations sur les commandes
Voici un exemple :
class Account(): def __init__(self, name, number): self.Name = name self.Number = number def display(self): print("Account # : {}\nAccount Name : {}".format(self.Number, self.Name)) class Customer(): def __init__(self, name, number): self.Name = name self.Number = number def display(self): print("Customer # : {}\nCustomer Name : {}".format(self.Number, self.Name)) class Orders(Account, Customer): def __init__(self, acctnumber, acctname, custnumber, custname, ordnumber, ordnamename, product, qty): self.OrdNumber = ordnumber self.Product = product self.Qty = qty self.OrdName = ordnamename self.acct = Account(acctname, acctnumber) self.cust = Customer(custname, custnumber) def display(self): print("Order Information") self.acct.display() self.cust.display() print("Order # : {}\nOrder Name : {}\nProduct : {}\nQuantiy : {}".format(self.OrdNumber, self.OrdName, self.Product, self.Qty)) acct = Account("AB Enterprise", 12345) acct.display() print("") cust = Customer("John Smith", 45678) cust.display() print("") order = Orders(12345, "AB Enterprise", 45678,"John Smith", 1, "Order 1", "Widget", 5, ) order.display()
Sortie :
Account # : 12345 Account Name : AB Enterprise Customer # : 45678 Customer Name : John Smith Order Information Account # : 12345 Account Name : AB Enterprise Customer # : 45678 Customer Name : John Smith Order # : 1 Order Name : Order 1 Product : Widget Quantiy : 5
Différents scénarios prioritaires
1 - Méthodes de classe
Les méthodes de classe sont spéciales dans le sens où elles peuvent être appelées sur une classe par elle-même ou par des instances d'une classe. Ils se lient à une classe, ce qui signifie que le premier argument passé à la méthode est une classe plutôt qu'une instance.
Les méthodes de classe sont écrites de la même manière que les méthodes d'instance régulières. Une différence est l'utilisation du décorateur @classmethod
pour identifier que la méthode est une méthode de classe. Aussi, par convention, au lieu d'utiliser self pour référencer l'instance d'une classe, cls
utilise pour référencer la classe. Par exemple :
class Account(): @classmethod def getClassVersion(cls): print("Account class version is 1.0”)
Pour plus d'informations sur les méthodes de classe, consultez ce site Web.
Voici un exemple du problème que vous rencontrerez lors de la redéfinition d'une méthode de classe :
class ParentClass: @classmethod def display(cls, arg): print("ParentClass") class SubClass(ParentClass): @classmethod def display(cls, arg): ret = ParentClass.create(cls, arg) print("Subclass") return ret SubClass.display("test")
Sortie :
create() takes 2 positional arguments but 3 were given
Dans le Subclass
, l'appel au ParentClass
La méthode create n'est pas un appel indépendant comme cela se produit avec une méthode d'instance normale. Le résultat de cet appel est une TypeError car la méthode a reçu trop d'arguments.
La solution est d'utiliser super()
afin d'utiliser avec succès l'implémentation parente.
class ParentClass: @classmethod def display(cls, arg): print("ParentClass") class SubClass(ParentClass): @classmethod def display(cls, arg): ret = super(SubClass, cls).create(arg) print("Subclass") return ret SubClass.display("test")
Sortie :
ParentClass Subclass
2 - Méthodes magiques
Que sont les méthodes magiques ?
Les méthodes magiques sont un ensemble de méthodes que Python associe automatiquement à chaque définition de classe. Vos classes peuvent remplacer ces méthodes magiques pour implémenter différents comportements et les faire agir comme les classes intégrées de Python. Vous trouverez ci-dessous des exemples de deux des plus courants :__str__
et __repl__
. À l'aide de ces deux méthodes, vous pouvez implémenter la façon dont vos objets sont affichés sous forme de chaînes, ce qui sera important lors du débogage et de la présentation des informations à l'utilisateur. Le remplacement de ces méthodes ajoute à la flexibilité et à la puissance de Python.
Le __str__
La méthode d'une classe est utilisée lorsque Python imprime un objet. Cette méthode magique est appelée par le str
fonction intégrée.
class DemoMagic(): def display(self): print("Demo Magic class") varDemo = DemoMagic() varDemo.display() str(varDemo)
Sortie :
Demo Magic class '<__main__.DemoMagic object at 0x000002A7A7F64408>' class DemoMagic(): def display(self): print("Demo Magic class") def __str__(self): return "Override of str function" varDemo = DemoMagic() varDemo.display() str(varDemo)
Sortie :
Demo Magic class 'Override of str function'
Le __repr__
La méthode d'une classe est utilisée pour afficher le détail des valeurs d'un objet. Cette méthode magique est appelée par la fonction intégrée repr
fonction.
class Person(object): def __init__(self, firstname, lastname): self.first = firstname self.last = lastname def __repr__(self): return "%s %s" % (self.first, self.last) Tom = Person("Tom", "Sawyer") repr(Tom)
Sortie
'Tom Sawyer'
Voici une liste de méthodes magiques. Vous pouvez en savoir plus à leur sujet ici (https://www.tutorialsteacher.com/python/magic-methods-in-python) et réfléchir à la manière de les remplacer pour répondre à vos besoins :
'__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', '__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__'
3 – Cours abstraits
Une classe abstraite est un plan que les sous-classes doivent suivre. Il peut être considéré comme un contrat entre la classe abstraite et la sous-classe. La classe abstraite vous dit quoi faire en fournissant une méthode abstraite vide et la sous-classe doit l'implémenter. Par défaut, vous devez remplacer les méthodes abstraites définies par la classe abstraite. En d'autres termes, nous fournissons une interface commune pour différentes implémentations d'une classe. Ceci est très utile pour les grands projets où certaines fonctionnalités doivent être implémentées.
Voici un exemple d'une classe abstraite et des méthodes surchargées dans les sous-classes.
from abc import ABC, abstractmethod class Animal(ABC): @abstractmethod def whoami(self): pass class Dog(Animal): def move(self): print("I am a dog") class Cat(Animal): def move(self): print("I am a cat")
Conclusion
Le remplacement est un concept de base utilisé à de nombreux endroits dans la programmation orientée objet. Vous devez le comprendre pour pouvoir implémenter de meilleures classes et modifier leur comportement. Cet article vous montre quelques exemples où vous pouvez utiliser des remplacements en Python. D'autres concepts mentionnés qui méritent d'être approfondis sont :la méthode magique et les classes abstraites.