Python - Orienté objet

Python est un langage orienté objet depuis qu'il existe. Pour cette raison, 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 de la prise en charge de la programmation orientée objet de Python.

Si vous n'avez aucune expérience préalable de la programmation orientée objet (OO), vous voudrez peut-être consulter un cours d'introduction à ce sujet ou au moins un didacticiel quelconque afin d'avoir une compréhension des concepts de base.

Cependant, voici une petite introduction de la programmation orientée objet (POO) pour vous apporter à la vitesse -

Aperçu de la terminologie de la POO

  • Class- Un 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.

  • Class variable- Une variable partagée par toutes les instances d'une classe. Les variables de classe sont définies dans une classe mais en dehors de l'une des méthodes de la classe. Les variables de classe ne sont pas utilisées aussi fréquemment que les variables d'instance.

  • Data member - Une variable de classe ou une variable d'instance qui contient les données associées à une classe et à ses objets.

  • Function overloading- L'affectation 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.

  • Instance variable - Une variable qui est définie dans une méthode et n'appartient qu'à l'instance actuelle d'une classe.

  • Inheritance - Le transfert des caractéristiques d'une classe vers d'autres classes qui en dérivent.

  • Instance- Un objet individuel d'une certaine classe. Un objet obj qui appartient à une classe Circle, par exemple, est une instance de la classe Circle.

  • Instantiation - La création d'une instance d'une classe.

  • Method - Un type spécial de fonction qui est défini dans une définition de classe.

  • Object- Une instance unique d'une structure de données 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.

  • Operator overloading - L'affectation de plus d'une fonction à un opérateur particulier.

Créer des classes

L' instruction de classe crée une nouvelle définition de classe. Le nom de la classe suit immédiatement la classe de mot-clé suivie de deux points comme suit -

class ClassName:
   'Optional class documentation string'
   class_suite
  • La classe a une chaîne de documentation, accessible via ClassName .__ doc__ .

  • La class_suite comprend toutes les instructions de composant définissant les membres de 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 classe this. Ceci est accessible en tant que Employee.empCount depuis l'intérieur de la classe ou en dehors de la classe.

  • La première méthode __init __ () est une méthode spéciale, 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 d'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 le nom de classe et transmettez les arguments acceptés par sa méthode __init__ .

"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éder aux attributs

Vous accédez aux attributs de l'objet à l'aide de l'opérateur point avec objet. La variable de classe serait accessible en utilisant le nom de classe comme suit -

emp1.displayEmployee()
emp2.displayEmployee()
print "Total Employee %d" % Employee.empCount

Maintenant, 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

"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:  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  # Add an 'age' attribute.
emp1.age = 8  # Modify 'age' attribute.
del emp1.age  # Delete 'age' attribute.

Au lieu d'utiliser les instructions normales pour accéder aux attributs, vous pouvez utiliser les fonctions suivantes -

  • le getattr(obj, name[, default]) - pour accéder à l'attribut d'objet.

  • le hasattr(obj,name) - pour vérifier si un attribut existe ou non.

  • le setattr(obj,name,value)- pour définir un attribut. Si l'attribut n'existe pas, il serait créé.

  • le delattr(obj, name) - pour supprimer un attribut.

hasattr(emp1, 'age')    # Returns true if 'age' attribute exists
getattr(emp1, 'age')    # Returns value of 'age' attribute
setattr(emp1, 'age', 8) # Set attribute 'age' at 8
delattr(empl, 'age')    # Delete attribute 'age'

Attributs de classe intégrés

Chaque classe Python continue de suivre les attributs intégrés et ils sont accessibles à l'aide de l'opérateur point comme tout autre attribut -

  • __dict__ - Dictionnaire contenant l'espace de noms de la classe.

  • __doc__ - Chaîne de documentation de classe ou aucune, si non dé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/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__

Lorsque le code ci-dessus est exécuté, il produit le résultat suivant -

Employee.__doc__: Common base class for all employees
Employee.__name__: Employee
Employee.__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>}

Détruire des objets (Garbage Collection)

Python supprime automatiquement les objets inutiles (types intégrés ou instances de classe) pour libérer de l'espace mémoire. Le processus par lequel Python récupère périodiquement des 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 est déclenché lorsque le nombre de références d'un objet atteint zéro. Le nombre de références d'un objet change à mesure que le nombre d'alias qui pointent vers lui change.

Le nombre de références d'un objet augmente lorsqu'il reçoit un nouveau nom ou 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 , sa référence est réaffectée ou sa référence est hors de 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 = [b]     # Increase ref. count  of <40> 

del a       # Decrease ref. count  of <40>
b = 100     # Decrease ref. count  of <40> 
c[0] = -1   # Decrease ref. count  of <40>

Vous ne remarquerez normalement pas quand le garbage collector 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 appelée lorsque l'instance est sur le point d'être détruite. Cette méthode peut ê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/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) # prints the ids of the obejcts
del pt1
del pt2
del pt3

Lorsque le code ci-dessus est exécuté, il produit le résultat suivant -

3083401324 3083401324 3083401324
Point destroyed

Note- Idéalement, vous devez définir vos classes dans un fichier séparé, puis les importer dans votre fichier programme principal à l'aide de l' instruction d' importation .

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 répertoriant la classe parente entre parenthèses après le nouveau nom de 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 un peu comme leur classe parente; cependant, une liste de classes de base à hériter est donnée après le nom de la classe -

class SubClassName (ParentClass1[, ParentClass2, ...]):
   'Optional class documentation string'
   class_suite

Exemple

#!/usr/bin/python

class 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.parentAttr

class Child(Parent): # define child class
   def __init__(self):
      print "Calling child constructor"

   def childMethod(self):
      print 'Calling child method'

c = Child()          # instance of child
c.childMethod()      # child calls its method
c.parentMethod()     # calls parent's method
c.setAttr(200)       # again call parent's method
c.getAttr()          # again call parent's method

Lorsque le code ci-dessus est exécuté, il produit le résultat suivant -

Calling child constructor
Calling child method
Calling parent method
Parent attribute : 200

De la même manière, 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 les relations de deux classes et instances.

  • le issubclass(sub, sup) La fonction booléenne renvoie true si la sous-classe donnée sub est en effet une sous-classe de la superclasse sup.

  • le isinstance(obj, Class)La fonction booléenne renvoie true si obj est une instance de classe Class ou est une instance d'une sous-classe de Class

Remplacer les méthodes

Vous pouvez toujours remplacer vos méthodes de classe parentes. L'une des raisons de remplacer les méthodes parentales est que vous souhaiterez peut-être des fonctionnalités spéciales ou différentes dans votre sous-classe.

Exemple

#!/usr/bin/python

class 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 child
c.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 répertorie certaines fonctionnalités génériques que vous pouvez remplacer dans vos propres classes -

N ° Sr. Méthode, description et exemple d'appel
1

__init__ ( self [,args...] )

Constructeur (avec tous les arguments facultatifs)

Exemple d'appel: obj = className (args)

2

__del__( self )

Destructor, supprime un objet

Exemple d'appel: del obj

3

__repr__( self )

Représentation sous forme de chaîne évaluable

Exemple d'appel: repr (obj)

4

__str__( self )

Représentation sous forme de chaîne imprimable

Exemple d'appel: str (obj)

5

__cmp__ ( self, x )

Comparaison d'objets

Exemple d'appel: 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 ajouter? Il est fort probable que Python vous crie dessus.

Vous pouvez, cependant, définir la méthode __add__ dans votre classe pour effectuer l'ajout de vecteurs, puis l'opérateur plus se comporterait comme prévu -

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

Lorsque le code ci-dessus est exécuté, il produit le résultat suivant -

Vector(7,8)

Masquage des données

Les attributs d'un objet peuvent être visibles ou non en dehors de la définition de classe. Vous devez nommer les attributs avec un double préfixe de soulignement, et ces attributs ne sont alors pas directement visibles pour les étrangers.

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

Lorsque le code ci-dessus est exécuté, il produit le résultat suivant -

1
2
Traceback (most recent call last):
   File "test.py", line 12, in <module>
      print counter.__secretCount
AttributeError: JustCounter instance has no attribute '__secretCount'

Python protège ces membres en modifiant le nom en interne pour inclure le nom de la classe. Vous pouvez accéder à des attributs tels que object._className__attrName . Si vous remplacez votre dernière ligne comme suit, cela fonctionne pour vous -

.........................
print counter._JustCounter__secretCount

Lorsque le code ci-dessus est exécuté, il produit le résultat suivant -

1
2
2