Introduction à la programmation orientée objet avec Python

Introduction

Ce tutoriel est une introduction aux concepts de la programmation orientée objet. Il fournit des explications concises, illustrées avec des exemples de code en Python.

Ce tutoriel est destiné aux personnes qui :

  • Connaissent déjà les concepts de classes et d'objets appliqués dans d'autres langages et qui souhaitent être opérationnelles rapidement en Python.
  • Ne connaissent pas les objets et qui souhaitent apprendre de façon simple et rapide (sans nécessairement voir tous les aspects théoriques de la programmation orientée objet).

Ce tutoriel n'est pas déstiné aux personnes qui :

  • souhaitent apprendre les concepts avancés de Python ou connaître les détails du fonctionnement de Python.

Si vous connaissez déjà le concept d'objets, vous pouvez passer l'introduction.

Qu'est-ce qu'un objet ?

Créer un objet revient à créer une structure de donnée (un type) à part entière.

Un objet peut contenir plusieurs variables (appelées attributs ou propriétés) qui permettent de stocker les données associées à un objet. Un objet peut aussi contenir un ensemble de fonctions qui lui sont rattachées (appelées méthodes) et qui permettent de manipuler les propriétés de l'objet.

Il est possible de créer plusieurs objets d'un même type (qu'on appellera une classe) et chacun de ces objets pourra avoir des valeurs différentes pour ses propriétés.

Si, par exemple, on développe un programme bancaire, on pourra créer un objet pour chacun des comptes utilisateurs. Ainsi, chaque utilisateur aurait un objet correspondant avec les informations qui lui sont rattachées.

objet_compte1 = CompteBancaire() # On crée deux objets
objet_compte2 = CompteBancaire()

print(objet_compte1.nom)  # On affiche le nom du compte 1
print(objet_compte1.solde)# On affiche le solde du compte 1

print(objet_compte2.nom)  # Là, on affiche le nom du deuxième compte
print(objet_compte2.solde)# Là, on affiche le solde du deuxième compte

Les deux objets qu'on a créé appartiennent à la même classe, ils possèdent donc la même structure avec les mêmes propriétés mais celles-ci ont des valeurs différentes.

Les objets disposent également de fonctions (méthodes) qui leur sont rattachées.

objet_compte1.effectuerRetrait(100)
objet_compte2.effectuerDépôt(300)

Les attributs et les méthodes d'un objet sont définis dans la définition de sa classe.

La programmation orientée objet (POO en français ou OOP en anglais) est une méthode de programmation qui vise à manipuler les objets afin de mieux résoudre certains problèmes.

Passons donc à la pratique.

Créer une classe avec des méthodes et des propriétés :

class CompteBancaire:
    """ Classe représentant un compte bancaire"""
 
   # une variable partagée par tous les objets de cette classe
    type = 'Compte normal'    

    def __init__(self, nom):
        #  variables par défaut, uniques pour chque objet :
        self.nom = nom
        self.solde = 0.0

    # Méthodes de l'objet :

    def afficherSolde(self):
        print self.solde
        return

    def effectuerRetrait(self, montant):
        self.solde -= montant
        return

    def effectuerDépôt(self, montant):
        self.solde += montant
        return

La méthode spéciale __init__() est appelée automatiquement lorsqu'un objet est créé.
Il est possible de lui passer des arguments qui seront utilisés pour initialiser l'objet créé avec certaines valeurs.

Créer un objet avec une classe et l'utiliser

objet1 = CompteBancaire("J1") # on crée une nouvelle instance
                                # avec le nom de la classe
objet2 = CompteBancaire("P2") # on crée une deuxième instance

# on utilise leurs propriétés
print(objet1.nom)    #'J1'
print(objet2.nom)    #'P2'

# Accéder aux méthodes d'un objet
objet1.effectuerDépôt(100)
objet2.effectuerDépôt(200)

print(objet1.solde)  # 'J1'
print(objet2.solde)  # 'P2'
# instructions équivalentes à :
objet1.afficherSolde() # 100
objet2.afficherSole()  # 200

print(objet1.type)  # 'Compte normal'
print(objet2.type)  # 'Compte normal'

Il est possible de déclarer une nouvelle propriété sur un seul des objets en affectant une valeur à une propriété choisie. Il est possible de supprimer une propriété d'un objet en utilisant del :

objet1.code_réduction = 'secret'

print(objet1.code_réduction) # 'secret'
print(objet2.code_réduction) # déclenche une erreur AttributeError: objet2 instance has no attribute 'code_réduction'

del objet1.discount_code # on remet dans son état précédent

Un peu de théorie

Vous réaliserez rapidement qu'en Python, tout est un objet. Cela signifie que tout ce que vous manipulez en Python a une classe. Pour déterminer la classe d'un objet, vous pouvez utiliser la propriété par défaut __class__ :

compte3 = CompteBancaire()
print(compte3.__class__) # __main__.CompteBancaire

string = 'Chat'
print(string.__class__)  # <type 'str'>

Dans un précédent article, on a vu [1,2].reverse() et effectivement, reverse() est une méthode de la classe native 'list' qui permet de représenter les listes.

L'héritage

Il est possible de faire « hériter » une classe d'une autre. Ainsi, la classe « fille » hérite des attributs et méthodes de la classe « parente » mais on peut également lui ajouter des propriétés et des méthodes qui lui seront propres (seule la classe fille en bénéficiera) :

class CompteProfessionnel( CompteBancaire ):
    # On « surcharge » l'attribut
    type = 'Compte professionnel'

    # On ajoute une fonctionnalité sous la forme d'une méthode
    def demanderCrédit(self, montant):
        self.solde += montant

pro = CompteProfessionnel()

Lorsqu'on accède aux propriétés d'un objet, l'interpréteur consulte la classe de l'objet. S'il ne trouve pas la propriété, il remonte la « chaîne d'héritage » pour analyser la classe parente et ainsi de suite jusqu'à ce qu'il trouve (ou non) la propriété recherchée.

Il est possible d'utiliser les propriétés originales d'une classe qu'on surcharge en préfixant du nom de la classe :

class CompteProSpécial( CompteProfessionnel ):
    def demanderCrédit(self, montant):
        self.solde = CompteProfessionnel.demanderCrédit(self, montant)
        return

Note : Les méthodes __init__() ne sont pas héritées.

On peut utiliser la fonction isinstance() pour vérifier qu'un objet est une instance d'une classe donnée ou d'une de ses sous-classes.
On peut utiliser la fonction issubclass() afin de vérifier qu'une classe hérite d'une autre classe :

isinstance(pro, CompteProfessionnel)         # True
isinstance(pro, CompteBancaire)              # True, classe héritée
issubclass(CompteProSpécial, CompteBancaire) # True

L'héritage multiple

Python permet de créer des classes qui héritent de plusieurs classes à la fois :

class ClassePersonnalisée( CompteProfessionnel, CompteInternational, ComptePrivilège):
    # . . .


Dans ce cas, si l'interpréteur ne trouve pas une propriété dans la classe de l'objet, il analysera les différentes classes parentes de la gauche vers la droite (dans l'exemple, le parcours commencera donc avec CompteProfessionnel avant de se poursuivre avec CompteInternational et ainsi de suite).

Les itérateurs

Comme nous l'avons déjà vu dans un article précédent, il est possible d'itérer sur les éléments d'un objet Python avec une boucle for :

for i in ['a', 'b', 'c']: print(i)
# 'a'
# 'b'
# 'c'

for i in 'abc': print(i) # notation identique

La fonction iter() peut être utilisée avec des objets spécifiques appelées itérateurs :

itérateur = iter('abc')
itérateur.next() # 'a'
itérateur.next() # 'b'
itérateur.next() # 'c'

Pour qu'un objet puisse être parcouru de cette façon, il suffit de définir le comportement de deux méthodes __iter__() et next() :

class CompteItérable( CompteBancaire ):
    def __init__(self, nom):
        self.nom = nom
        self.index = len(self.nom)

    def __iter__(self):
        return self

    def next(self):
        # l'itérateur parcourera le nom 
        # dans l'ordre inverse
        if self.index == 0:
            raise StopIteration
        self.index -= 1
        return self.nom[self.index]

itérable = CompteItérable('pile')
for i in itérable: print(i)
# 'e'
# 'l'
# 'i'
# 'p'

 

Étiquettes et contributeurs liés au document

 Contributeurs à cette page : SphinxKnight
 Dernière mise à jour par : SphinxKnight,