Aller au contenu

Programmation orientée objet

Classes, instances et attributs

Une classe définit et nomme une structure de donnée qui vient s'ajouter aux autres structures de données du langage. Cela permet de regrouper ensemble plusieurs éléments qui ont un lien entre eux, comme on pourrait le faire avec un p-uplet nommé ou un dictionnaire. On utilise pour cela le mot clé class, suivit d'un nom commençant par une majuscule (le nom de la classe), puis des deux points. Le reste du code de la classe est indenté. La fonction __init__ (définie à l'intérieur de la classe) est appelée le constructeur de la classe. Elle permet de générer des instances (ou objet) de la classe, ici les deux variables nemo et dory.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class Poisson:
    """ Représente un poisson """
    def __init__(self, n, t, f=False):
        """ Poisson, str, int, bool -> None """
        self.nom = n
        self.poids = t
        self.faim = f

nemo = Poisson("Nemo", 15)
dory = Poisson("Dory", 15, f=True)

À retenir. Si le constructeur d'une classe C est du type __init__(self, arg1, arg2), on construit un nouvel élément de type C à l'aide de l'instruction C(arg1, arg2).

1
2
print(nemo)
print(dory)
<__main__.Poisson object at 0x7fa5f71a2dd0>
<__main__.Poisson object at 0x7fa5f72bbf70>

img

À retenir. Si objet est une instance de la classe C, alors il est possible d'accéder et de modifier un attribut avec la syntaxe objet.attribut (parfois appelée notation pointée).

1
2
3
4
print(nemo.nom)
print(nemo.faim)
nemo.faim = True
print(nemo.faim)
Nemo
False
True

Écrire une fonction nourrir qui prend en argument un objet p de type Poisson et qui simule l'effet d'un repas sur le poisson :

  • si le poisson a faim, la poids du poisson augmente de \(1\) et le poisson n'a plus faim ;
  • si le poisson n'a pas faim, rien ne se passe.

Méthodes et interface

Une méthode d'une classe est une fonction définie dans cette classe, qui permet de manipuler les objets de cette classe. Son premier argument est donc toujours un objet de la classe, par convention nommé self. Une méthode peut accepter un nombre quelconque de paramètres.

On appelle l'ensemble des méthodes que l'on peut appliquer à un objet l'interface de l'objet. Dans le paradigme de la programmation orientée objet, un programme qui manipule un objet n'est pas censé accéder à la totalité de son contenu (ses attributs) : il doit passer par son interface pour interagir avec lui.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Poisson:
    """ Représente un poisson """
    def __init__(self, n, t, f=False):
        """ Poisson, str, int, bool -> None """
        self.nom = n
        self.poids = t
        self.faim = f

    def présente(self):
        """ Poisson -> None """
        print(f"Bonjour, je suis {self.nom} !")

    def nourrir(self):
        """ Poisson -> None """
        if self.faim:
            self.poids += 1
            self.faim = False

    def est_pêchable(self, poids_client):
        return self.poids >= poids_client

    def __str__(self):
        """ Poisson -> str """
        return f"<Poisson {self.nom}. Poids : {self.poids}, affamé : {self.faim}>"
1
2
3
4
nemo = Poisson("Nemo", 15)
dory = Poisson("Dory", 15, f=True)
nemo.présente()
dory.présente()
Bonjour, je suis Nemo !
Bonjour, je suis Dory !

À retenir. Il est possible d'accéder aux méthodes d'une classe depuis n'importe quel objet de la classe, avec la syntaxe objet.méthode(arg1, arg2). On n'écrit pas objet.méthode(self, arg1, arg2) : le premier argument est toujours l'objet auquel la méthode s'applique.

  1. Comment transformer la fonction nourrir définie précédemment en une méthode de la classe Poisson ?

  2. Écrire une méthode est_pêchable de la classe Poisson qui prend en argument un entier poids_client (représentant le poids voulu par le client) et qui renvoie True si le poisson est suffisamment lourd (c'est à dire si son poids est supérieur ou égal à poids_client), et False sinon.

Méthodes spéciales et erreurs

Méthodes spéciales

Certaines méthodes en python ont un rôle particulier : on les reconnaît à leur nom encadré de deux symboles _ (on les appelle parfois méthodes dunder). C'est par exemple le cas de la méthode __init__ qui est appelée automatiquement à la création d'un nouvel objet de la classe. Une fois ces méthodes définies, il est possible de les appeler avec une syntaxe plus "naturelle".

Méthode Appel Description
__str__(self) str(o) Renvoie une chaîne de caractère décrivant l'objet o
__len__(self) len(o) Renvoie un entier définissant la taille de l'objet o
__lt__(self, a) o < a Renvoie True si o est strictement plus petit que a
__add__(self, a) o + a Renvoie la somme de o et a.

Objets identiques et aliassage

Attention, en python les objets sont dits mutables (on peut changer les valeurs de leurs attributs). Cela mène au phénomène d'aliassage, lorsque deux variables font référence au même objet.

1
2
3
4
dory2 = dory
dory.nourrir()
print(dory)
print(dory2)
<Poisson Dory. Poids : 16, affamé : False>
<Poisson Dory. Poids : 16, affamé : False>

Erreurs classiques

Attribut non définit dans la méthode __init__

1
nemo.taille
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Input In [32], in <cell line: 1>()
----> 1 nemo.taille

AttributeError: 'Poisson' object has no attribute 'taille'

Confusion entre attribut et méthode

1
nemo.poids()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Input In [33], in <cell line: 1>()
----> 1 nemo.poids()

TypeError: 'int' object is not callable

Confusion entre méthode et attribut

1
nemo.présente
<bound method Poisson.présente of <__main__.Poisson object at 0x7fa5f72ad390>>