Aller au contenu

Chapitre 3 : Programmation objet⚓︎

Carnet Jupyter à télécharger ici (bientôt disponible)

Parmi les types de base étudiés en Première et que nous avons l'habitude de manipuler, on peut citer :

  • des types simples comme les types numériques entier (int) et flottant (float), le type booléen (bool) ou le type chaîne de caractères (str),
  • des types construits comme les types tableau (list), p-uplet (tuple) et dictionnaire (dict).

Le type d'un objet détermine ce qu'on peut faire avec, par exemple :

  • l'opérateur + peut s'utiliser entre deux nombres, entre deux chaînes, entre deux tableaux, mais pas entre un nombre et une chaîne...
  • append peut s'utiliser pour ajouter un élément à la fin d'un tableau, mais pas à la fin d'une chaîne ou d'un puplet...
  • len donne la longueur d'une chaîne, d'un tableau, d'un p-uplet ou d'un dictionnaire, mais pas d'un nombre ou d'un booléen...
  • etc.

Le but de ce chapitre est d'apprendre à définir nos propres types personnalisés, appelés classes, dont nous pourrons décider de la structure et des utilisations possibles.

Création d'une classe⚓︎

On crée une classe appelée Montre en écrivant class Montre:. Par convention, les noms de classes sont de la forme NomDeClasse, avec une majuscule au début de chaque mot, sans espace entre les mots.

1
2
class Montre:
    """Pour l'instant, la classe est vide et ne sert à rien..."""

On peut désormais créer une variable ma_montre de "type" Montre. Plus précisément, on dit que ma_montre est une instance de la classe Montre.

1
ma_montre = Montre()

L'intérêt d'une classe est que ses instances peuvent posséder des attributs, qui permettent de stocker des données, et des méthodes, qui permettent de modifier ces données.

La partie de la documentation officielle de Python qui traite des classes commence comme ceci :

Classes provide a means of bundling data and functionality together. Creating a new class creates a new type of object, allowing new instances of that type to be made. Each class instance can have attributes attached to it for maintaining its state. Class instances can also have methods (defined by its class) for modifying its state.

On souhaite que les instances de la classe Montre possèdent trois attributs h, m et s. Pour cela, on définit une méthode, dite méthode constructeur et nommée __init__, qui est appelée automatiquement lors de la création d'une instance de la classe.

L'initialisation des attributs peut se faire avec des valeurs par défaut, par exemple 0.

1
2
3
4
5
6
7
8
class Montre:
    def __init__(self):
        """Méthode constructeur initialisant les attributs à la valeur par défaut 0."""
        self.h = 0
        self.m = 0
        self.s = 0

ma_montre = Montre() # création d'une instance de la classe Montre

La première ligne d'une méthode est semblable à celle d'une fonction : def nom_methode(parametres):.

Le paramètre self est toujours le premier paramètre d'entrée d'une méthode (et c'est parfois le seul, comme ici). Il représente l'instance sur laquelle la méthode est appelée.

Pour accéder à la valeur d'un attribut, la syntaxe à utiliser est instance.attribut.

L'initialisation des attributs peut se faire avec des valeurs choisies au moment de la création de l'instance de classe.

1
2
3
4
5
6
7
8
class Montre:
    def __init__(self, h, m, s):
        """Méthode constructeur initialisant les attributs aux valeurs h, m, s passées en argument."""
        self.h = h
        self.m = m
        self.s = s

ma_montre = Montre(13, 30, 0) # création d'une instance de la classe Montre

La méthode __init__ possède ici quatre paramètres d'entrée, le premier étant self. On remarque néanmoins que, lors de la création de l'instance ma_montre, seules trois valeurs (qui correspondent à h, m et s sont passées en arguments.

Définition de méthodes⚓︎

On peut ajouter à la classe Montre la définition de méthodes dont le rôle est de permettre de modifier les instances de la classe.

Par exemple, le rôle de la méthode incrémenter est d'avancer la montre d'une seconde.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
class Montre:
    def __init__(self, h, m, s):
        """Méthode constructeur initialisant les attributs aux valeurs h, m, s passées en argument."""
        self.h = h
        self.m = m
        self.s = s

    def incrementer(self):
        """Avance la montre d'une seconde."""
        if self.s < 59:
            self.s += 1
        else:
            self.s = 0
            if self.m < 59:
                self.m += 1
            else:
                self.m = 0
                if self.h < 23:
                    self.h += 1
                else:
                    self.h = 0

Lorsque la méthode incrementer est appelée pour une instance de la classe Montre, la valeur de l'attribut s est modifiée pour cette instance. La valeur des attributs m et h peut être modifiée également.

La syntaxe instance.methode() permet d'appeler une méthode qui ne prend pas d'argument en entrée (autre que self).

Le rôle de la méthode avancer est d'avancer la montre de plusieurs secondes.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Montre:
    def __init__(self, h, m, s):
        """Méthode constructeur initialisant les attributs aux valeurs h, m, s passées en argument."""
        self.h = h
        self.m = m
        self.s = s

    def incrementer(self):
        """Avance la montre d'une seconde."""
        if self.s < 59:
            self.s += 1
        else:
            self.s = 0
            if self.m < 59:
                self.m += 1
            else:
                self.m = 0
                if self.h < 23:
                    self.h += 1
                else:
                    self.h = 0

    def avancer(self, n):
        """Avance la montre de n secondes."""
        for _ in range(n):
            self.incrementer()

Lorsque la méthode avancer est appelée pour une instance de la classe Montre, la méthode incrementer est appelée n fois pour cette instance elle-même (d'où la commande self.incrementer().

La syntaxe instance.methode(arguments) permet d'appeler une méthode qui prend un ou plusieurs arguments en entrée (autres que self).

La fonction localtime du module time permet de connaître l'heure locale au moment de l'appel de la fonction. L'objet renvoyé possède (entre autres) trois attributs tm_hour, tm_min et tm_sec qui donnent respectivement l'heure, les minutes et les secondes de l'heure locale.

On peut ajouter à la définition de la classe Montre une méthode synchroniser dont le rôle est de mettre la montre à l'heure.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
from time import localtime

class Montre:
    def __init__(self, h, m, s):
        """Méthode constructeur initialisant les attributs aux valeurs h, m, s passées en argument."""
        self.h = h
        self.m = m
        self.s = s

    def synchroniser(self):
        """Synchronise la montre à l'heure locale du moment de l'appel."""
        heure_locale = localtime()
        self.h = heure_locale.tm_hour
        self.m = heure_locale.tm_min
        self.s = heure_locale.tm_sec

Lorsque la méthode synchroniser est appelée pour une instance de la classe Montre, la valeur des attributs h, m et s est modifiée pour cette instance.

Si on souhaite afficher à l'écran l'heure de la montre, on peut se demander ce que donnerait l'instruction print(ma_montre).

L'affichage obtenu <__main__.Montre object at 0x7f45dc1f9350> n'est pas lisible, hormis la référence au fait que ma_montre est un objet de "type" Montre.

Il est néanmoins possible de faire apparaître un affichage personnalisé beaucoup plus lisible de l'objet en définissant une méthode spéciale nommée __str__.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class Montre:
    def __init__(self, h, m, s):
        """Méthode constructeur initialisant les attributs aux valeurs h, m, s passées en argument."""
        self.h = h
        self.m = m
        self.s = s

    def __str__(self):
        """Affiche l'heure de la montre au format HH:MM:SS."""
        return f"{self.h}:{self.m}:{self.s}"

La méthode spéciale __str__ est crée pour être appelée par la fonction print. Elle doit donc renvoyer une chaîne de caractères.

Ce qu'il faut savoir et savoir faire⚓︎

  • Connaître le vocabulaire de la programmation objet, en particulier la notion de classe, d'instance, d'attribut et de méthode.
  • Utiliser la notation pointée instance.attribut et instance.methode(arguments).
  • Définir une classe, créer une instance et gérer l'initialisation des attributs d'instance grâce à la méthode __init__.
  • Définir une méthode et comprendre l'utilisation du paramètre self.

Exercices et activités⚓︎

Exercices

Carnet Jupyter à travailler sur le site CAPYTALE ou à télécharger ici

Corrigé disponible ici

Carnet Jupyter à travailler sur le site CAPYTALE ou à télécharger ici

Corrigé disponible ici

Carnet Jupyter à travailler sur le site CAPYTALE ou à télécharger ici

Corrigé bientôt disponible ici

Carnet Jupyter à télécharger ici

Corrigé bientôt disponible ici

Activités

L'objectif de l'activité est de faire rebondir une balle dans une fenêtre graphique.

Balle rebondissante

Carnet Jupyter à télécharger ici

⚠️ Le fichier balle_pygame.py doit être placé dans le même répertoire que le carnet act_balle_rebondissante.ipynb.

Corrigé disponible ici

L'objectif de l'activité est de représenter des fractales célèbres : l'ensemble de Mandelbrot et les ensembles de Julia.

Ensemble de Mandelbrot

Carnet Jupyter à travailler sur le site CAPYTALE ou à télécharger ici

Corrigé disponible ici

L'objectif de cette activité est de définir et d'utiliser une classe Fraction puis de travailler sur les fractions égyptiennes.

Fractions égyptiennes

Carnet Jupyter à travailler sur le site CAPYTALE ou à télécharger ici

Corrigé disponible ici

(bientôt disponible)

Paquet de cartes

Carnet Jupyter à travailler sur le site CAPYTALE ou à télécharger ici

Corrigé bientôt disponible ici