Python >> Tutoriel Python >  >> Python

Remplacement en Python

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 du Account 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.