Chapitre 2 : POO et classes.

🕐 Historique:

  • Origines (années 1960): Le concept de POO a été initié par le langage Simula, développé par Ole-Johan Dahl et Kristen Nygaard en Norvège. Simula introduit les notions de classes et d'héritage.
  • Popularisation (années 1970-1980): Smalltalk, développé par Alan Kay et d'autres au Xerox PARC, est le premier langage entièrement orienté objet. Il introduit des concepts tels que l'encapsulation, le polymorphisme et l'héritage.
  • Normalisation (années 1990): Avec l'émergence de langages tels que C++ et Java, la POO devient un standard dans le développement logiciel. Java popularise la POO avec sa plateforme permettant d'écrire un code une fois et de l'exécuter partout.
  • Évolution et diversification: La POO a été intégrée dans de nombreux autres langages de programmation, incluant Python, Ruby, et PHP. Les principes de POO ont été adaptés et étendus, contribuant à l'évolution continue des techniques de développement logiciel.

Aujourd'hui, la POO reste un pilier fondamental du développement logiciel, influençant la conception de systèmes logiciels complexes et la manière dont les développeurs pensent la résolution de problèmes informatiques.

Source : wikipedia

1. Paradigmes de programmation:

A copier dans le cahier.

Un paradigme de programmation est la façon dont un programme (ou un bout de programme) est construit.

2. Exemples:

Vous avez vu jusque là deux paradigmes de programmation : la programmation impérative et la programmation fonctionnelle.

Voici deux façons de compter le nombre de fois où la lettre "c" est présente dans 'coucou':

3. POO:

A copier dans le cahier.

Les lettres POO signifient Programmation Orientée Objet. C'est un troisième paradigme de programmation.

Cela désigne la possibilité dans un langage informatique à créer divers objets avec des propriétés et des méthodes associées.

Née en 1960, cette possibilité s'est démocratisée dans les années 1990.

4. Les classes d'objets dans Python:

Dans Python, pour créer des objets qui ne sont pas naturellement présent, on utilise l'instruction class.

Celui-ci doit impérativement contenir "le constructeur" def __init__(self): .

Une "bonne pratique" est de distinguer les mots d'un nom de classe en mettant des majuscules au début de chaque mot. Par exemple CompteBancaire, ArbreBinaire etc.

5. Méthodes, attributs:

Lorsque l'on crée une class, on peut y ajouter des méthodes et des attributs.

class Joueur:
    def __init__(self,pseudo):
        self.pseudo=pseudo        #ceci est un attribut
        self.points_de_vie=1000    #ceci est un attribut

    def change_pseudo(self,nouveau_pseudo):        #ceci est une méthode
        self.pseudo=nouveau_pseudo

    def get_pseudo(self):        #ceci est une méthode
        return self.pseudo

Par exemple, dans le code ci-dessus, on peut faire appel à l'attribut joueur1.pseudo ou encore à la méthode joueur1.get_pseudo()

6. Exercice :

Dans cet exercice, vous allez créer une classe CompteBancaire pour simuler la gestion d'un compte bancaire :

  • Chaque compte a un titulaire et un solde initial.
  • Implémentez une méthode pour déposer de l'argent sur le compte.
  • Implémentez une méthode pour retirer de l'argent du compte, en veillant à ne pas autoriser un solde négatif.
  • Implémentez une méthode pour afficher le solde actuel du compte.
  1. Complétez la classe CompteBancaire.
  2. Créez une instance avec le titulaire "Jean Dupont" et un solde initial de 1000 euros.
  3. Effectuez un dépôt de 250 euros, puis un retrait de 500 euros et affichez le solde après ces opérations.
  4. Essayez de retirer un montant supérieur au solde disponible et gérez cette situation dans votre code.
class CompteBancaire: def __init__(self, titulaire, solde_initial): .... def deposer(self, montant): .... def retirer(self, montant): if ....: self.solde -= montant else: print("Fonds insuffisants") def afficher_solde(self): ... # Exemple d'utilisation compte = CompteBancaire("Jean Dupont", 1000) compte.deposer(250) compte.retirer(500) compte.afficher_solde() compte.retirer(2000) # Retrait impossible

Tests :

Affichage :

Console:



    
>>>

7. Méthodes/attributs privés ou publiques:

A copier dans le cahier.

Lorsque l'on crée une classe, on peut avoir des méthodes ou des attributs privés. Ils ne sont alors pas accessibles depuis l'extérieur de la classe.

Dans Python, une méthode ou un attribut est par défaut publique mais peut être passé en privé en rajoutant __ devant.

8. Exemple:

class Joueur:
    def __init__(self,nom):
        self.pseudo=self.__crea_nom(nom)
        self.__point_de_vie=100
    
    def affiche_pv(self):
        return self.__point_de_vie

    def __crea_nom(self,mot):
        if mot=="aucun":
            return "Anonyme"
        else:
            return mot

Dans le code ci-dessus :

9. Exercice :

Dans cet exercice, vous allez créer une classe Livre pour gérer les informations d'une bibliothèque :

  • Le titre et l'auteur sont des attributs publics.
  • L'annee_publication est un attribut privé, vérifié lors de l'initialisation pour s'assurer qu'elle est inférieur ou égale à 2030.
  • La méthode affiche_info() doit afficher le titre, l'auteur et l'année de publication.
  • La méthode privée __verifie_annee() est utilisée pour valider l'année.
  1. Complétez la définition de la classe Livre.
  2. Créez deux instances de Livre avec les informations suivantes :
    • Livre 1 : Titre "Les Misérables", Auteur "Victor Hugo", Année de publication 1862.
    • Livre 2 : Titre "1984", Auteur "George Orwell", Année de publication 1949.
  3. Utilisez la méthode affiche_info() pour afficher les informations de chaque livre.
  4. Essayez d'accéder directement à l'attribut privé __annee_publication pour observer ce qui se passe.
class Livre: def __init__(self, titre, auteur, annee_publication): self.titre = .. .. if self.__verifie_annee(annee_publication): .. else: self.__annee_publication = None def affiche_info(self): .. def __verifie_annee(self, annee): .. # Exemple d'utilisation livre1 = ..

Tests :

Affichage :

Console:



    
>>>

10. Exercice : (sujet 20 - 2025)

On dispose d’une classe Carte permettant de créer des objets modélisant des cartes à jouer.

Complète la classe Paquet_de_cartes ci-dessous :

  • Le constructeur doit créer un paquet de 52 cartes (13 valeurs pour chaque couleur : pique, cœur, carreau, trèfle).
  • La méthode get_carte(pos) doit renvoyer la carte à la position donnée.
  • Ajoute une assertion pour vérifier que pos est bien compris entre 0 et 51.

⭐ Exemples :

>>> jeu = Paquet_de_cartes()
>>> carte1 = jeu.get_carte(20)
>>> print(carte1.get_valeur() + " de " + carte1.get_couleur())
8 de coeur
>>> carte2 = jeu.get_carte(0)
>>> print(carte2.get_valeur() + " de " + carte2.get_couleur())
As de pique
>>> carte3 = jeu.get_carte(52)
AssertionError: paramètre pos invalide
class Carte: def __init__(self, c, v): """ Initialise les attributs couleur (1 à 4), et valeur (1 à 13). """ self.couleur = c self.valeur = v def get_valeur(self): valeurs = ["As", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Valet", "Dame", "Roi"] return valeurs[self.valeur - 1] def get_couleur(self): couleurs = ["pique", "coeur", "carreau", "trèfle"] return couleurs[self.couleur - 1] class Paquet_de_cartes: def __init__(self): """ Crée un paquet de 52 cartes classées par valeurs croissantes, d'abord pique, puis coeur, carreau et trèfle. """ .. .. .. .. def get_carte(self, pos): """ Renvoie la carte à la position pos (0 ≤ pos ≤ 51). """ .. .. # Exemple d'utilisation jeu = Paquet_de_cartes() c1 = jeu.get_carte(20) print(c1.get_valeur(), "de", c1.get_couleur()) # 8 de coeur

Tests :

Affichage :

Console:



    
>>>

11. Exercice : (sujet 41 - 2025)

Dans cet exercice, on appelle carré d’ordre n un tableau de n lignes et n colonnes dont chaque case contient un entier naturel.

Exemples :

1 7
7 1

c2

Un carré d'ordre 2

3 4 5
4 4 4
5 4 3

c3

Un carré d'ordre 3

2 9 4
7 0 3
6 1 8

c3bis

Un autre carré d'ordre 3

Un carré est dit semimagique lorsque les sommes des éléments situés sur chaque ligne et chaque colonne sont égales.

  • Ainsi c2 et c3 sont semimagiques car la somme de chaque ligne et chaque colonne est égale à 8 pour c2 et 12 pour c3.
  • Le carré c3bis n’est pas semimagique car la somme de la première ligne est égale à 15 alors que celle de la deuxième ligne est égale à 10.

La classe Carre en page suivante contient des méthodes qui permettent de manipuler des carrés :

  • La méthode constructeur crée un carré sous forme d’un tableau à deux dimensions à partir d’une liste d’entiers, et d’un ordre.
  • La méthode affiche permet d’afficher le carré créé.

Exemples :

>>> liste = (3, 4, 5, 4, 4, 4, 5, 4, 3)
>>> c3 = Carre(liste, 3)
>>> c3.affiche()
[3, 4, 5]
[4, 4, 4]
[5, 4, 3]

Compléter la méthode est_semimagique qui renvoie True si le carré est semimagique, False sinon. Puis tester la fonction est_semimagique sur les carrés c2, c3 et c3bis.

# Carrés fournis c2 = [1, 7, 7, 1] c3 = [3, 4, 5, 4, 4, 4, 5, 4, 3] c3bis = [2, 9, 4, 7, 0, 3, 6, 1, 8] class Carre: def __init__(self, liste, n): self.ordre = n self.tableau = [[liste[i + j * n] for i in range(n)] for j in range(n)] def affiche(self): """Affiche le carré""" for i in range(self.ordre): print(self.tableau[i]) def somme_ligne(self, i): """Somme des valeurs de la ligne i""" somme = 0 for j in range(self.ordre): somme = somme + self.tableau[i][j] return somme def somme_col(self, j): """Somme des valeurs de la colonne j""" somme = 0 for i in range(self.ordre): somme = somme + self.tableau[i][j] return somme def est_semimagique(self): s = self.somme_ligne(0) # test de la somme de chaque ligne for i in range(....): if self.somme_ligne(i) != ....: return .... # test de la somme de chaque colonne for j in range(....): if self.somme_col(j) != ....: return .... return .... # Exemples d'utilisation (tu peux modifier ou commenter) C2 = Carre(c2, 2) C3 = Carre(c3, 3) C3B = Carre(c3bis, 3) print(C2.est_semimagique(), C3.est_semimagique(), C3B.est_semimagique())

Tests :

Affichage :

Console:



    
>>>

12. Sujet écrit ASIE 2025

A faire dans le cahier.

Pour travailler sur des dates, on a créé la classe Date dont le code est écrit ci-dessous

class Date:
    def __init__(self, jour, mois, annee):
        self.jour = ...
        self.mois = ...
        self.annee = ...
        self.nb_jours_par_mois = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]


    def get_jour(self):
        return self.jour


    def get_mois(self):
        return self.mois

        
    def get_annee(self):
        return ...
    
        
    def set_jour(self, jour):
        self.jour = jour

        
    def set_mois(self, mois):
        self.mois = ...

        
    def set_annee(self, annee):
        self.annee = annee

        
    def est_bissextile(self):
        ...
    

Partie A : Accès et modification des données

Le constructeur de la classe Date prend en paramètres trois entiers représentant le jour, le mois et l’année, puis les affecte respectivement aux attributs jour, mois et annee.

  1. Recopier et compléter les lignes deux premières lignes du constructeur.
  2. Indiquer à quelle date correspond l’instance de la classe Date suivante :

    d = Date(1, 5, 2000)

  3. Écrire le code permettant de créer une instance d de la classe Date qui représente la date du 19 juin 2024.

  4. La méthode get_annee renvoie la valeur de l’attribut annee.

    Recopier et compléter les lignes de la méthode get_annee.

  5. La méthode set_mois modifie l’attribut mois en lui affectant la valeur passée en argument.

    Recopier et compléter les lignes de la méthode set_mois.

L’attribut nb_jours_par_mois contient une liste qui correspond au nombre de jours pour chaque mois.

Le mois de février contient généralement 28 jours mais lors des années bissextiles il en contient 29.

  1. La classe Date dispose d’une méthode est_bissextile, qui utilise uniquement l’attribut annee, et qui renvoie True si l’année de l’instance courante est bissextile et False sinon. On veut compléter la méthode __init__ pour ajuster le nombre de jours par mois pour les années bissextiles.

    Recopier et compléter les lignes suivantes :

    class Date:
        def __init__(self, jour, mois, annee):
            self.jour = ...
            self.mois = ...
            self.annee = ...
            self.nb_jours_par_mois = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
            if .... :
                self.nb_jours_par_mois[...] = 29

Partie B : sur l’année de l’instance courante

Pour déterminer le nombre de jours au cours d’une année, il faut savoir si elle est bissextile.

Une année est bissextile si elle est divisible par 4 mais pas par 100 ou si elle est divisible par 400.

  1. Écrire le code de la méthode est_bissextile.

    On rappelle qu’un entier a est divisible par l’entier n si a % n == 0.

On dote la classe Date de la méthode nb_jours_passes qui renvoie le nombre de jours passés dans l’année de l’instance courante.

def nb_jours_passes(self):
    nb_jours = self.jour
    mois = self.mois - 2
    while mois >= 0:
        nb_jours = nb_jours + self.nb_jours_par_mois[mois]
        mois = mois - 1
    return nb_jours
  1. Indiquer quel sera l’affichage en console après l’exécution des deux instructions suivantes :

    >>> d1 = Date(20, 3, 2001)
    >>> d1.nb_jours_passes()
                

On dote la classe Date de la méthode nb_jours_restants qui renvoie le nombre de jours restants dans l’année de l’instance courante, soit 366 ou 365 moins le nombre de jours déjà passés, selon que l’année est bissextile ou non.

  1. Recopier et compléter le script de la méthode nb_jours_restants ci-après :

    def nb_jours_restants(self):
        j = 365
        if ...:
            j = 366
        return j -    ...

Partie C : entre deux dates

On dote la classe Date de la méthode nb_jours_depuis qui prend en paramètre une autre instance other de la classe Date et qui renvoie le nombre de jours écoulés entre la date de l’instance other et la date de l’instance courante.

def nb_jours_depuis(self, other):
    if other.get_annee() > self.get_annee():
        return -1
    if other.get_annee() == self.get_annee():
        if other.nb_jours_passes() > self.nb_jours_passes() :
            return -1
        if other.nb_jours_passes() == self.nb_jours_passes() :
            return 0
    nb_jours = self.nb_jours_passes() + other.nb_jours_restants()
    for annee in range(other.get_annee()+1, self.get_annee()):
        d_suivant = date(1, 1, annee)
        if d_suivant.est_bissextile():
            nb_jours += 366
        else:
            nb_jours += 365
    return nb_jours

On crée les instances de la classe Date suivantes :


>>> d1 = Date(15, 6, 2024)
>>> d2 = Date(15, 6, 2024)
>>> d3 = Date(15, 7, 2024)
>>> d4 = Date(15, 6, 2025)
>>> d5 = Date(15, 6, 2022)
  1. Indiquer quels seront alors les affichages en console après l’exécution de chacune des instructions suivantes (on précise que l’année 2024 est bissextile) :
    >>> d1.nb_jours_depuis(d2)
    >>> d1.nb_jours_depuis(d3)
    >>> d1.nb_jours_depuis(d4)
    >>> d1.nb_jours_depuis(d5)
    

Le timestamp est le nombre de secondes qui se sont écoulées depuis le 1er janvier 1970 à 00h00. Il s’agit de la date de la mise en marche du système d’exploitation UNIX.

Par exemple, le 01/01/2024 à 00:00:00 correspond au timestamp de 1704063600.

  1. Recopier et compléter le code de la méthode timestamp qui renvoie le nombre de secondes qui se sont écoulées depuis le 1er janvier 1970.
    def timestamp(self):
        d = ...
        return self.nb_jours_depuis(d) * 24 * 3600
    

13. Projet:

Projet : créer un programme Python faisant intervenir les classes.

Consignes :