Python est un langage orienté objet depuis qu’il existe. De ce fait, la création et l’utilisation de classes et d’objets sont carrément faciles. Ce chapitre vous aide à devenir un expert dans l’utilisation du support de programmation orientée objet de Python.
Si vous n’avez pas d’expérience préalable de la programmation orientée objet (OO), vous pouvez consulter un cours d’introduction à ce sujet ou au moins un tutoriel quelconque afin de maîtriser les concepts de base.
Cependant, voici une petite introduction de la programmation orientée objet (POO) pour vous mettre à niveau –
Vue d’ensemble de la terminologie de la POO
-
Classe – Prototype défini par l’utilisateur pour un objet qui définit un ensemble d’attributs qui caractérisent tout objet de la classe. Les attributs sont des membres de données (variables de classe et variables d’instance) et des méthodes, accessibles via la notation par points.
-
Variable de classe – Une variable qui est partagée par toutes les instances d’une classe. Les variables de classe sont définies à l’intérieur d’une classe mais en dehors de toute méthode de la classe. Les variables de classe ne sont pas utilisées aussi fréquemment que les variables d’instance.
-
Membre de données – Une variable de classe ou une variable d’instance qui contient des données associées à une classe et à ses objets.
-
Surcharge de fonctions – L’attribution de plus d’un comportement à une fonction particulière. L’opération effectuée varie selon les types d’objets ou d’arguments impliqués.
-
Variable d’instance – Une variable qui est définie à l’intérieur d’une méthode et qui n’appartient qu’à l’instance actuelle d’une classe.
-
Héritage – Le transfert des caractéristiques d’une classe à d’autres classes qui en sont dérivées.
-
Instance – Un objet individuel d’une certaine classe. Un objet obj qui appartient à une classe Cercle, par exemple, est une instance de la classe Cercle.
-
Instanciation – La création d’une instance d’une classe.
-
Méthode – Une sorte spéciale de fonction qui est définie dans une définition de classe.
-
Objet – Une instance unique d’une structure de données qui est définie par sa classe. Un objet comprend à la fois des membres de données (variables de classe et variables d’instance) et des méthodes.
-
Surcharge d’opérateurs – L’affectation de plus d’une fonction à un opérateur particulier.
Création de classes
L’instruction class crée une nouvelle définition de classe. Le nom de la classe suit immédiatement le mot-clé class suivi d’un deux-points comme suit –
class ClassName: 'Optional class documentation string' class_suite
-
La classe possède une chaîne de documentation, à laquelle on peut accéder via ClassName.__doc__.
-
La classe_suite se compose de toutes les déclarations de composants définissant les membres de la classe, les attributs de données et les fonctions.
Exemple
Voici l’exemple d’une classe Python simple –
class Employee: 'Common base class for all employees' empCount = 0 def __init__(self, name, salary): self.name = name self.salary = salary Employee.empCount += 1 def displayCount(self): print "Total Employee %d" % Employee.empCount def displayEmployee(self): print "Name : ", self.name, ", Salary: ", self.salary
-
La variable empCount est une variable de classe dont la valeur est partagée entre toutes les instances d’une cette classe. On peut y accéder sous la forme Employee.empCount depuis l’intérieur ou l’extérieur de la classe.
-
La première méthode __init__() est une méthode spéciale, qui est appelée constructeur de classe ou méthode d’initialisation que Python appelle lorsque vous créez une nouvelle instance de cette classe.
-
Vous déclarez les autres méthodes de classe comme des fonctions normales, à l’exception du fait que le premier argument de chaque méthode est self. Python ajoute l’argument self à la liste pour vous ; vous n’avez pas besoin de l’inclure lorsque vous appelez les méthodes.
Création d’objets d’instance
Pour créer des instances d’une classe, vous appelez la classe en utilisant class name et vous passez les arguments que sa méthode __init__ accepte.
"This would create first object of Employee class"emp1 = Employee("Zara", 2000)"This would create second object of Employee class"emp2 = Employee("Manni", 5000)
Accès aux attributs
Vous accédez aux attributs de l’objet en utilisant l’opérateur point avec object. La variable de classe serait accessible en utilisant le nom de la classe comme suit –
emp1.displayEmployee()emp2.displayEmployee()print "Total Employee %d" % Employee.empCount
Maintenant, en mettant tous les concepts ensemble –
#!/usr/bin/pythonclass Employee: 'Common base class for all employees' empCount = 0 def __init__(self, name, salary): self.name = name self.salary = salary Employee.empCount += 1 def displayCount(self): print "Total Employee %d" % Employee.empCount def displayEmployee(self): print "Name : ", self.name, ", Salary: ", self.salary"This would create first object of Employee class"emp1 = Employee("Zara", 2000)"This would create second object of Employee class"emp2 = Employee("Manni", 5000)emp1.displayEmployee()emp2.displayEmployee()print "Total Employee %d" % Employee.empCount
Lorsque le code ci-dessus est exécuté, il produit le résultat suivant –
Name : Zara ,Salary: 2000Name : Manni ,Salary: 5000Total Employee 2
Vous pouvez ajouter, supprimer, ou modifier les attributs des classes et des objets à tout moment –
emp1.age = 7 # Add an 'age' attribute.emp1.age = 8 # Modify 'age' attribute.del emp1.age # Delete 'age' attribute.
Au lieu d’utiliser les déclarations normales pour accéder aux attributs, vous pouvez utiliser les fonctions suivantes –
-
La getattr(obj, name) – pour accéder à l’attribut de l’objet.
-
The hasattr(obj,name) – pour vérifier si un attribut existe ou non.
-
The setattr(obj,name,value) – pour définir un attribut. Si l’attribut n’existe pas, alors il serait créé.
-
Le delattr(obj, nom) – pour supprimer un attribut.
hasattr(emp1, 'age') # Returns true if 'age' attribute existsgetattr(emp1, 'age') # Returns value of 'age' attributesetattr(emp1, 'age', 8) # Set attribute 'age' at 8delattr(empl, 'age') # Delete attribute 'age'
Attributs de classe intégrés
Chaque classe Python conserve les attributs intégrés suivants et on peut y accéder en utilisant l’opérateur point comme n’importe quel autre attribut –
-
__dict__ – Dictionnaire contenant l’espace de noms de la classe.
-
__doc__ – Chaîne de documentation de la classe ou aucune, si elle est indéfinie.
-
__name__ – Nom de la classe.
-
__module__ – Nom du module dans lequel la classe est définie. Cet attribut est « __main__ » en mode interactif.
-
__bases__ – Un tuple éventuellement vide contenant les classes de base, dans l’ordre de leur occurrence dans la liste des classes de base.
Pour la classe ci-dessus, essayons d’accéder à tous ces attributs –
#!/usr/bin/pythonclass Employee: 'Common base class for all employees' empCount = 0 def __init__(self, name, salary): self.name = name self.salary = salary Employee.empCount += 1 def displayCount(self): print "Total Employee %d" % Employee.empCount def displayEmployee(self): print "Name : ", self.name, ", Salary: ", self.salaryprint "Employee.__doc__:", Employee.__doc__print "Employee.__name__:", Employee.__name__print "Employee.__module__:", Employee.__module__print "Employee.__bases__:", Employee.__bases__print "Employee.__dict__:", Employee.__dict__
Lorsque le code ci-dessus est exécuté, il produit le résultat suivant –
Employee.__doc__: Common base class for all employeesEmployee.__name__: EmployeeEmployee.__module__: __main__Employee.__bases__: ()Employee.__dict__: {'__module__': '__main__', 'displayCount':<function displayCount at 0xb7c84994>, 'empCount': 2, 'displayEmployee': <function displayEmployee at 0xb7c8441c>, '__doc__': 'Common base class for all employees', '__init__': <function __init__ at 0xb7c846bc>}
Destruction des objets (Garbage Collection)
Python supprime automatiquement les objets inutiles (types intégrés ou instances de classe) pour libérer l’espace mémoire. Le processus par lequel Python récupère périodiquement les blocs de mémoire qui ne sont plus utilisés est appelé Garbage Collection.
Le garbage collector de Python s’exécute pendant l’exécution du programme et se déclenche lorsque le nombre de références d’un objet atteint zéro. Le nombre de références d’un objet change en fonction du nombre d’alias qui pointent vers lui.
Le nombre de références d’un objet augmente lorsqu’un nouveau nom lui est attribué ou lorsqu’il est placé dans un conteneur (liste, tuple ou dictionnaire). Le nombre de références de l’objet diminue lorsqu’il est supprimé avec del, que sa référence est réaffectée ou que sa référence sort de la portée. Lorsque le nombre de références d’un objet atteint zéro, Python le collecte automatiquement.
a = 40 # Create object <40>b = a # Increase ref. count of <40> c = # Increase ref. count of <40> del a # Decrease ref. count of <40>b = 100 # Decrease ref. count of <40> c = -1 # Decrease ref. count of <40>
Vous ne remarquerez normalement pas lorsque le ramasseur d’ordures détruit une instance orpheline et récupère son espace. Mais une classe peut implémenter la méthode spéciale __del__(), appelée destructeur, qui est invoquée lorsque l’instance est sur le point d’être détruite. Cette méthode pourrait être utilisée pour nettoyer toutes les ressources non-mémoire utilisées par une instance.
Exemple
Ce destructeur __del__() imprime le nom de classe d’une instance qui est sur le point d’être détruite –
#!/usr/bin/pythonclass Point: def __init__( self, x=0, y=0): self.x = x self.y = y def __del__(self): class_name = self.__class__.__name__ print class_name, "destroyed"pt1 = Point()pt2 = pt1pt3 = pt1print id(pt1), id(pt2), id(pt3) # prints the ids of the obejctsdel pt1del pt2del pt3
Lorsque le code ci-dessus est exécuté, il produit le résultat suivant –
3083401324 3083401324 3083401324Point destroyed
Note – Idéalement, vous devriez définir vos classes dans un fichier séparé, puis vous devriez les importer dans votre fichier de programme principal en utilisant l’instruction import.
Héritage de classe
Au lieu de partir de zéro, vous pouvez créer une classe en la dérivant d’une classe préexistante en indiquant la classe parent entre parenthèses après le nom de la nouvelle classe.
La classe enfant hérite des attributs de sa classe parent, et vous pouvez utiliser ces attributs comme s’ils étaient définis dans la classe enfant. Une classe enfant peut également remplacer les membres de données et les méthodes du parent.
Syntaxe
Les classes dérivées sont déclarées à peu près comme leur classe parent ; cependant, une liste de classes de base dont hériter est donnée après le nom de la classe –
class SubClassName (ParentClass1): 'Optional class documentation string' class_suite
Exemple
#!/usr/bin/pythonclass Parent: # define parent class parentAttr = 100 def __init__(self): print "Calling parent constructor" def parentMethod(self): print 'Calling parent method' def setAttr(self, attr): Parent.parentAttr = attr def getAttr(self): print "Parent attribute :", Parent.parentAttrclass Child(Parent): # define child class def __init__(self): print "Calling child constructor" def childMethod(self): print 'Calling child method'c = Child() # instance of childc.childMethod() # child calls its methodc.parentMethod() # calls parent's methodc.setAttr(200) # again call parent's methodc.getAttr() # again call parent's method
Lorsque le code ci-dessus est exécuté, il produit le résultat suivant –
Calling child constructorCalling child methodCalling parent methodParent attribute : 200
De façon similaire, vous pouvez piloter une classe à partir de plusieurs classes parentes comme suit –
class A: # define your class A.....class B: # define your class B.....class C(A, B): # subclass of A and B.....
Vous pouvez utiliser les fonctions issubclass() ou isinstance() pour vérifier une relation entre deux classes et instances.
-
La fonction booléenne issubclass(sub, sup) renvoie vrai si la sous-classe donnée sub est bien une sous-classe de la superclasse sup.
-
La fonction booléenne isinstance(obj, Class) renvoie vrai si obj est une instance de la classe Class ou est une instance d’une sous-classe de Class
Overriding Methods
Vous pouvez toujours surcharger les méthodes de votre classe parent. Une raison pour surcharger les méthodes du parent est que vous pouvez vouloir une fonctionnalité spéciale ou différente dans votre sous-classe.
Exemple
#!/usr/bin/pythonclass Parent: # define parent class def myMethod(self): print 'Calling parent method'class Child(Parent): # define child class def myMethod(self): print 'Calling child method'c = Child() # instance of childc.myMethod() # child calls overridden method
Lorsque le code ci-dessus est exécuté, il produit le résultat suivant –
Calling child method
Méthodes de surcharge de base
Le tableau suivant énumère certaines fonctionnalités génériques que vous pouvez surcharger dans vos propres classes –
Sr.No. | Méthode, description &Appel d’exemple |
---|---|
1 |
__init__ ( self ) Constructeur (avec tout argument facultatif) Appel d’exemple : obj = className(args) |
2 |
__del__( self ) Destructeur, supprime un objet Appel type : del obj |
3 |
__repr__( self ) Représentation de chaîne de caractères évaluable Appel d’exemple : repr(obj) |
4 |
__str__( self ) Représentation de chaîne de caractères imprimable Appel à titre d’exemple : str(obj) |
5 |
__cmp__( self, x ) Comparaison d’objets Appel simple : cmp(obj, x) |
Surcharge des opérateurs
Supposons que vous ayez créé une classe Vector pour représenter des vecteurs à deux dimensions, que se passe-t-il lorsque vous utilisez l’opérateur plus pour les additionner ? Très probablement, Python vous criera dessus.
Vous pourriez, cependant, définir la méthode __add__ dans votre classe pour effectuer l’addition de vecteurs et alors l’opérateur plus se comporterait comme prévu –
Exemple
#!/usr/bin/pythonclass Vector: def __init__(self, a, b): self.a = a self.b = b def __str__(self): return 'Vector (%d, %d)' % (self.a, self.b) def __add__(self,other): return Vector(self.a + other.a, self.b + other.b)v1 = Vector(2,10)v2 = Vector(5,-2)print v1 + v2
Lorsque le code ci-dessus est exécuté, il produit le résultat suivant –
Vector(7,8)
Data Hiding
Les attributs d’un objet peuvent ou non être visibles en dehors de la définition de la classe. Vous devez nommer les attributs avec un préfixe à double soulignement, et ces attributs ne sont alors pas directement visibles par des personnes extérieures.
Exemple
#!/usr/bin/pythonclass JustCounter: __secretCount = 0 def count(self): self.__secretCount += 1 print self.__secretCountcounter = JustCounter()counter.count()counter.count()print counter.__secretCount
Lorsque le code ci-dessus est exécuté, il produit le résultat suivant –
12Traceback (most recent call last): File "test.py", line 12, in <module> print counter.__secretCountAttributeError: JustCounter instance has no attribute '__secretCount'
Python protège ces membres en modifiant en interne le nom pour inclure le nom de la classe. Vous pouvez accéder à de tels attributs comme object._className__attrName. Si vous remplacez votre dernière ligne par la suivante, alors cela fonctionne pour vous –
.........................print counter._JustCounter__secretCount
Lorsque le code ci-dessus est exécuté, il produit le résultat suivant –
.