Maîtriser la programmation orientée objet en Python : Guide complet
Python est un langage orienté objet depuis son origine. Créer et utiliser des classes et des objets est donc très simple. Ce chapitre vous aide à devenir expert dans l'utilisation du support de la programmation orientée objet (POO) de Python.
Si vous n'avez aucune expérience de la programmation orientée objet (POO), consultez un cours d'introduction ou au moins un tutoriel pour saisir les concepts de base.
Voici une petite introduction à la POO pour vous mettre à niveau :
Vue d'ensemble de la terminologie POO
Classe : Prototype défini par l'utilisateur pour un objet, définissant un ensemble d'attributs caractérisant tout objet de la classe. Les attributs sont des membres de données (variables de classe et d'instance) et des méthodes, accessibles via la notation par point.
Variable de classe : Variable partagée par toutes les instances d'une classe. Définie dans la classe mais en dehors des méthodes. Moins fréquentes que les variables d'instance.
Membre de données : Variable de classe ou d'instance contenant des données associées à une classe et ses objets.
Surcharge de fonction : Attribution de plusieurs comportements à une fonction particulière. L'opération varie selon les types d'objets ou d'arguments.
Variable d'instance : Variable définie à l'intérieur d'une méthode et appartenant uniquement à l'instance courante d'une classe.
Héritage : Transfert des caractéristiques d'une classe à d'autres classes qui en dérivent.
Instance : Objet individuel d'une certaine classe. Un objet
objappartenant à une classeCircleest une instance deCircle.Instanciation : Création d'une instance d'une classe.
Méthode : Type spécial de fonction définie dans une définition de classe.
Objet : Instance unique d'une structure de données définie par sa classe. Un objet comprend membres de données (variables de classe et d'instance) et méthodes.
Surcharge d'opérateur : Attribution de plusieurs fonctions à 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 de deux points :
class ClassName:
'Optional class documentation string'
class_suite
La classe a une chaîne de documentation, accessible via
ClassName.__doc__.Le
class_suiteconsiste en toutes les instructions définissant les membres de classe, attributs de données et fonctions.
Exemple
Voici un exemple de 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
empCountest une variable de classe dont la valeur est partagée entre toutes les instances. Accessible viaEmployee.empCount.La première méthode
__init__()est une méthode spéciale, appelée constructeur ou méthode d'initialisation, que Python appelle lors de la création d'une nouvelle instance.Vous déclarez les autres méthodes comme des fonctions normales, sauf que le premier argument de chaque méthode est
self. Python ajoute l'argumentselfautomatiquement ; vous n'avez pas besoin de l'inclure lors de l'appel.
Création d'objets instances
Pour créer des instances d'une classe, appelez la classe en utilisant son nom et passez les arguments acceptés par sa méthode __init__ :
# Ceci créerait le premier objet de la classe Employee
emp1 = Employee("Zara", 2000)
# Ceci créerait le second objet
emp2 = Employee("Manni", 5000)
Accès aux attributs
Vous accédez aux attributs de l'objet via l'opérateur point. Les variables de classe sont accessibles via le nom de la classe :
emp1.displayEmployee()
emp2.displayEmployee()
print("Total Employee %d" % Employee.empCount)
En rassemblant tous les concepts :
#!/usr/bin/python
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)
emp1 = Employee("Zara", 2000)
emp2 = Employee("Manni", 5000)
emp1.displayEmployee()
emp2.displayEmployee()
print("Total Employee %d" % Employee.empCount)
Résultat :
Name : Zara ,Salary: 2000
Name : Manni ,Salary: 5000
Total Employee 2
Vous pouvez ajouter, supprimer ou modifier des attributs de classes et d'objets à tout moment :
emp1.age = 7 # Ajouter un attribut 'age'
emp1.age = 8 # Modifier 'age'
del emp1.age # Supprimer 'age'
Au lieu d'utiliser les instructions normales, vous pouvez utiliser les fonctions suivantes :
getattr(obj, name[, default]) : accéder à l'attribut d'un objet.
hasattr(obj, name) : vérifier si un attribut existe.
setattr(obj, name, value) : définir un attribut. S'il n'existe pas, il sera créé.
delattr(obj, name) : supprimer un attribut.
hasattr(emp1, 'age') # True si 'age' existe
getattr(emp1, 'age') # Valeur de 'age'
setattr(emp1, 'age', 8) # Définir 'age' à 8
delattr(emp1, 'age') # Supprimer 'age'
Attributs de classe intégrés
Chaque classe Python conserve les attributs intégrés suivants, accessibles via l'opérateur point :
__dict__ : Dictionnaire contenant l'espace de noms de la classe.
__doc__ : Chaîne de documentation de la classe ou
Nonesi non définie.__name__ : Nom de la classe.
__module__ : Nom du module où la classe est définie.
"__main__"en mode interactif.__bases__ : Tuple contenant les classes de base, dans l'ordre de leur occurrence.
Pour la classe ci-dessus, accédons à ces attributs :
#!/usr/bin/python
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)
print("Employee.__doc__:", Employee.__doc__)
print("Employee.__name__:", Employee.__name__)
print("Employee.__module__:", Employee.__module__)
print("Employee.__bases__:", Employee.__bases__)
print("Employee.__dict__:", Employee.__dict__)
Résultat :
Employee.__doc__: Common base class for all employees
Employee.__name__: Employee
Employee.__module__: __main__
Employee.__bases__: ()
Employee.__dict__: {'__module__': '__main__', 'displayCount': , 'empCount': 2, 'displayEmployee': , '__doc__': 'Common base class for all employees', '__init__': }
Destruction d'objets (Ramasse-miettes)
Python supprime automatiquement les objets inutiles (types intégrés ou instances de classes) pour libérer l'espace mémoire. Le processus par lequel Python récupère périodiquement les blocs de mémoire plus utilisés s'appelle la collecte des ordures (Garbage Collection).
Le ramasse-miettes s'exécute pendant le programme et se déclenche quand le compteur de références d'un objet atteint zéro. Ce compteur change selon le nombre d'alias pointant vers l'objet.
Le compteur augmente quand l'objet reçoit un nouveau nom ou est placé dans un conteneur (liste, tuple, dictionnaire). Il diminue quand l'objet est supprimé avec del, sa référence réassignée, ou sort de portée. À zéro, Python le collecte automatiquement.
a = 40 # Créer objet <40>
b = a # Augmenter ref. count de <40>
c = [b] # Augmenter ref. count de <40>
del a # Diminuer ref. count de <40>
b = 100 # Diminuer ref. count de <40>
c[0] = -1 # Diminuer ref. count de <40>
Vous ne remarquerez normalement pas quand le ramasse-miettes détruit une instance orpheline. Mais une classe peut implémenter la méthode spéciale __del__(), appelée destructeur, invoquée quand l'instance est sur le point d'être détruite. Cette méthode peut nettoyer les ressources non-mémoire utilisées par une instance.
Exemple
Ce destructeur __del__() affiche le nom de la classe d'une instance sur le point d'être détruite :
#!/usr/bin/python
class 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 = pt1
pt3 = pt1
print(id(pt1), id(pt2), id(pt3))
del pt1
del pt2
del pt3
Résultat :
3083401324 3083401324 3083401324
Point destroyed
Note : Idéalement, définissez vos classes dans un fichier séparé, puis importez-les dans votre programme principal avec import.
Héritage de classe
Au lieu de partir de zéro, créez une classe en la dérivant d'une classe préexistante en listant la classe parente entre parenthèses après le nom de la nouvelle classe.
La classe enfant hérite des attributs de sa classe parente et peut les utiliser comme si elles étaient définies dans la classe enfant. Une classe enfant peut aussi redéfinir des membres de données et des méthodes du parent.
Syntaxe
class SubClassName (ParentClass1[, ParentClass2, ...]):
'Optional class documentation string'
class_suite
Exemple
#!/usr/bin/python
class Parent:
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.parentAttr)
class Child(Parent):
def __init__(self):
print("Calling child constructor")
def childMethod(self):
print('Calling child method')
c = Child()
c.childMethod()
c.parentMethod()
c.setAttr(200)
c.getAttr()
Résultat :
Calling child constructor
Calling child method
Calling parent method
Parent attribute : 200
De même, vous pouvez dériver une classe de plusieurs classes parentes :
class A:
# définir votre classe A .....
class B:
# définir votre classe B .....
class C(A, B):
# sous-classe de A et B .....
Utilisez issubclass() ou isinstance() pour vérifier les relations entre classes et instances :
issubclass(sub, sup) : renvoie
Truesisubest bien une sous-classe desup.isinstance(obj, Class) : renvoie
Truesiobjest une instance deClassou d'une sous-classe.
Redéfinition de méthodes
Vous pouvez toujours redéfinir les méthodes de votre classe parente. Une raison : vous voulez une fonctionnalité spéciale ou différente dans votre sous-classe.
Exemple
#!/usr/bin/python
class Parent:
def myMethod(self):
print('Calling parent method')
class Child(Parent):
def myMethod(self):
print('Calling child method')
c = Child()
c.myMethod()
Résultat :
Calling child method
Méthodes de base surchargeables
Le tableau suivant liste quelques fonctionnalités génériques que vous pouvez redéfinir dans vos classes :
| N° | Méthode, description et exemple d'appel |
|---|---|
| 1 | __init__(self[, args...]) Constructeur (avec arguments optionnels) Appel : |
| 2 | __del__(self) Destructeur, supprime un objet Appel : |
| 3 | __repr__(self) Représentation chaîne évaluable Appel : |
| 4 | __str__(self) Représentation chaîne affichable Appel : |
| 5 | __cmp__(self, x) Comparaison d'objets Appel : |
Surcharge d'opérateurs
Supposons que vous ayez créé une classe Vector pour représenter des vecteurs 2D. Que se passe-t-il avec l'opérateur plus ? Python protestera probablement.
Vous pouvez définir la méthode __add__ dans votre classe pour effectuer l'addition vectorielle, et l'opérateur plus se comportera comme attendu :
Exemple
#!/usr/bin/python
class 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)
Résultat :
Vector(7, 8)
Masquage des données
Les attributs d'un objet peuvent être visibles ou non en dehors de la définition de la classe. Nommez les attributs avec un double underscore comme préfixe, et ils ne seront pas directement visibles depuis l'extérieur.
Exemple
#!/usr/bin/python
class JustCounter:
__secretCount = 0
def count(self):
self.__secretCount += 1
print(self.__secretCount)
counter = JustCounter()
counter.count()
counter.count()
print(counter.__secretCount)
Résultat :
1
2
Traceback (most recent call last):
File "test.py", line 12, in
print(counter.__secretCount)
AttributeError: JustCounter instance has no attribute '__secretCount'
Python protège ces membres en changeant internement le nom pour inclure le nom de la classe. Vous pouvez accéder à de tels attributs via object._className__attrName. Si vous remplacez la dernière ligne par :
print(counter._JustCounter__secretCount)
Résultat :
1
2
2
Python
- Classes et objets C# : Fondations pour une POO robuste
- Maîtriser les types de données Python : Guide pratique
- Maîtriser les opérateurs Python : Guide complet
- Maîtriser l'instruction pass en Python : Guide pratique
- Maîtriser les dictionnaires Python : création, manipulation et techniques avancées
- Maîtriser les exceptions personnalisées Python : guide pratique
- Maîtriser la programmation orientée objet Python : classes, héritage, encapsulation et polymorphisme
- Le pattern Singleton en Java expliqué : implémentation et utilisation sûre
- Suivi d'objets automatisé par vision avec Raspberry Pi et OpenCV