Exercice Corrigé: Les classes POO Python – Partie 3

Cet exercice de programmation orientée objet (POO) a pour but de vous aider à apprendre et à pratiquer les concepts de la POO. Toutes les questions sont testées sur Python 3.

Python La programmation orientée objet (POO) est basée sur le concept d’« objets », qui peuvent contenir des données et du code : des données sous la forme de variables d’instance (souvent connues sous le nom d’attributs ou de propriétés), et du code, sous la forme de méthodes. En d’autres termes, la POO permet d’encapsuler des propriétés et des comportements connexes dans des objets individuels.
 
 

Exercice 1:

Écrivez un programme Python pour créer une classe qui représente une forme. Incluez des méthodes pour calculer sa surface et son périmètre. Implémentez des sous-classes pour différentes formes comme le triangle, le cercle et le carré.

Solution:

# Importer le module math pour accéder à des fonctions mathématiques telles que pi
import math

# Définir une classe de base appelée Forme pour représenter une forme générique avec des méthodes de calcul de surface et du périmètre.
class Forme:
    # Méthode de calcul de surface (à implémenter dans les classes filles)
    def calculer_surface(self):
        pass

    # Méthode de calcul de périmètre (à implémenter dans les classes filles)
    def calculer_perimeter(self):
        pass

# Définir une classe fille appelée Cercle, qui hérite de la classe Forme.
class Cercle(Forme):
    # Initialiser l'objet Cercle avec un rayon donné
    def __init__(self, rayon):
        self.rayon = rayon

    # Calculez et donnez la surface du cercle à l'aide de la formule: π * r^2
    def calculer_surface(self):
        return math.pi * self.rayon**2

    # Calculez et donnez le périmètre du cercle à l'aide de la formule: 2π * r
    def calculer_perimeter(self):
        return 2 * math.pi * self.rayon

# Définir une classe fille appelée Rectangle, qui hérite de la classe Forme.
class Rectangle(Forme):
    # Initialiser l'objet Rectangle avec une longueur et une largeur données
    def __init__(self, longueur, largeur):
        self.longueur = longueur
        self.largeur = largeur

    # Calculer et renvoyer la surface du rectangle en utilisant la formule: longueur * largeur
    def calculer_surface(self):
        return self.longueur * self.largeur

    # Calculer et renvoyer le périmètre du rectangle à l'aide de la formule: 2 * (longueur + largeur)
    def calculer_perimeter(self):
        return 2 * (self.longueur + self.largeur)

# Définir une classe fille appelée Triangle, qui hérite de la classe Forme.
class Triangle(Forme):
    # Initialiser l'objet Triangle avec une base, une hauteur et trois longueurs de côté
    def __init__(self, base, hauteur, cote1, cote2, cote3):
        self.base = base
        self.hauteur = hauteur
        self.cote1 = cote1
        self.cote2 = cote2
        self.cote3 = cote3

    # Calculez et renvoyez la surface du triangle à l'aide de la formule: 0,5 * base * hauteur
    def calculer_surface(self):
        return 0.5 * self.base * self.hauteur

    # Calculer et renvoyer le périmètre du triangle en additionnant les longueurs de ses trois côtés
    def calculer_perimeter(self):
        return self.cote1 + self.cote2 + self.cote3


# Créer un objet Cercle avec un rayon donné et calculer sa surface et son périmètre
r = 7
c = Cercle(r)
s = c.calculer_surface()
p = c.calculer_perimeter()

# Afficher les résultats pour le cercle
print("Rayon du cercle:", r)
print("Surface du cercle:", s)
print("Périmètre du cercle:", p)

# Créer un objet Rectangle avec une longueur et une largeur données et calculer sa surface et son périmètre.
long = 5
larg = 7
rectangle = Rectangle(long, larg)
s = rectangle.calculer_surface()
p = rectangle.calculer_perimeter()

# Afficher les résultats pour le Rectangle
print("\nRectangle: Longueur", long, " Largeur =", larg)
print("Surface du rectangle:", s)
print("Périmètre du rectangle:", p)

# Créer un objet Triangle avec une base, une hauteur et trois longueurs de côté, et calculer sa surface et son périmètre.
base = 5
hauteur = 4
c1 = 4
c2 = 3
c3 = 5

# Afficher les résultats pour le Triangle
print("\nTriangle: Base =", base, " Hauteur =", hauteur, " cote1 =", c1, " cote2 =", c2, " cote3 =", c3)
triangle = Triangle(base, hauteur, c1, c2, c3)
s = triangle.calculer_surface()
p = triangle.calculer_perimeter()
print("Surface du triangle:", s)
print("Périmètre du triangle:", p)

Sortie:

Rayon du cercle: 7
Surface du cercle: 153.93804002589985
Périmètre du cercle: 43.982297150257104

Rectangle: Longueur 5  Largeur = 7
Surface du rectangle: 35
Périmètre du rectangle: 24

Triangle: Base = 5  Hauteur = 4  cote1 = 4  cote2 = 3  cote3 = 5
Surface du triangle: 10.0
Périmètre du triangle: 12

Explication:

Dans l’exercice ci-dessus,

  • Nous définissons une classe de base appelée Forme qui sert de modèle aux autres formes. Elle comprend deux méthodes, calculer_surface et calculer_perimeter, qui sont surchargées par les sous-classes.
  • La classe Cercle est une sous-classe de Forme et comprend une logique conçue pour calculer la surface et le périmètre d’un cercle en utilisant le rayon fourni.
  • La classe Rectangle, une autre sous-classe de la classe Forme, comprennent des attributs de longueur et de largeur qui leur permettent de calculer leur surface et leur périmètre.
  • La classe Triangle est également une sous-classe de Forme et comprend les attributs nécessaires (base, hauteur et longueur des côtés) pour calculer la surface et le périmètre d’un triangle.
  • Dans l’exemple d’utilisation, nous créons des instances de chaque sous-classe et appelons les méthodes calculer_surface et calculer_perimeter pour obtenir les valeurs de la surface et du périmètre. Les résultats sont ensuite affichés.
 

Exercice 2:

Ecrivez un programme Python pour créer une classe Book avec les attributs suivants: Titre, Nom auteur, Prix. Définir un constructeur puis définir la méthode display() pour afficher les informations d’une instance Book.

Solution:

class Book:
     def __init__(self, titre, nom, prix):
          self.titre = titre
          self.nom = nom
          self.prix = prix
         
     def display(self):
          print("Titre:",self.titre,"\nNom auteur:",self.nom,"\nPrix:",self.prix)
         

b = Book("Le Bruit et la Fureur", "Alex Babtise", "5€")         
b.display()

Sortie:

Titre: Le Bruit et la Fureur 
Nom auteur: Alex Babtise 
Prix: 5€
 

Exercice 3:

Écrivez un programme Python pour créer une classe représentant un arbre de recherche binaire. Incluez des méthodes d’insertion et de recherche d’éléments dans l’arbre binaire.

Un arbre de recherche binaire, également appelé arbre binaire ordonné ou trié, est une structure de données binaire enracinée dont la clé de chaque nœud interne est supérieure à toutes les clés du sous-arbre gauche du nœud concerné et inférieure à celles de son sous-arbre droit. La complexité temporelle des opérations sur l’arbre de recherche binaire est directement proportionnelle à la hauteur de l’arbre.

Solution:

# Définir une classe appelée Node pour représenter un nœud dans un arbre de recherche binaire.
class Node:
    # Initialiser l'objet Node avec une valeur, et mettre les pointeurs des fils de gauche et de droite à None.
    def __init__(self, value):
        self.value = value
        self.left = None
        self.right = None

    # Définir une méthode __str__ personnalisée pour convertir la valeur du nœud en une chaîne de caractères.
    def __str__(self):
        return str(self.value)

# Définir une classe appelée BinarySearchTree pour représenter un arbre de recherche binaire.
class BinarySearchTree:
    # Initialiser l'arbre avec un nœud racine vide
    def __init__(self):
        self.root = None

    # Insérer une valeur dans l'arbre
    def insert(self, value):
        # Si la racine est None, créer un nouveau nœud avec la valeur donnée comme racine.
        if self.root is None:
            self.root = Node(value)
        else:
            self._insert_recursive(self.root, value)

    # Méthode pour insérer récursivement une valeur dans l'arbre
    def _insert_recursive(self, node, value):
        if value < node.value:
            if node.left is None:
                node.left = Node(value)
            else:
                self._insert_recursive(node.left, value)
        elif value > node.value:
            if node.right is None:
                node.right = Node(value)
            else:
                self._insert_recursive(node.right, value)

    # Recherche d'une valeur dans l'arbre
    def search(self, value):
        return self._search_recursive(self.root, value)

    # Méthode pour rechercher de manière récursive une valeur dans l'arbre et renvoyer le nœud s'il est trouvé.
    def _search_recursive(self, node, value):
        if node is None or node.value == value:
            return node
        if value < node.value:
            return self._search_recursive(node.left, value)
        else:
            return self._search_recursive(node.right, value)


# Créer une instance de BinarySearchTree
arbre = BinarySearchTree()

# Insérer des valeurs dans l'arbre
arbre.insert(8)
arbre.insert(10)
arbre.insert(3)
arbre.insert(6)
arbre.insert(1)
arbre.insert(14)
arbre.insert(4)
arbre.insert(7)
arbre.insert(13)

# Recherche d'éléments dans l'arbre et afficher les résultats
print("Recherche d'éléments:")
print(arbre.search(4))
print(arbre.search(5))

Sortie:

4
None

Explication:

Dans l'exercice ci-dessus,

  • Nous définissons une classe Node représentant un nœud dans l'arbre de recherche binaire. Chaque nœud contient une valeur, ainsi que des références à ses nœuds enfants de gauche et de droite.
  • La classe BinarySearchTree représente l'arbre de recherche binaire lui-même. Elle possède un attribut root qui pointe vers le nœud racine de l'arbre.
  • La méthode « insert() » insère une nouvelle valeur dans l'arbre. Si l'arbre est vide (la racine est None), elle crée un nouveau nœud et en fait la racine. Sinon, elle appelle la méthode insertrecursive pour parcourir l'arbre de manière récursive et trouver la position appropriée pour insérer la nouvelle valeur.
  • La méthode « insertrecursive() » compare la valeur à insérer avec la valeur du nœud actuel et décide s'il faut aller à gauche ou à droite dans l'arbre. Si l'enfant de gauche ou de droite est None, elle crée un nouveau nœud et en fait l'enfant. Sinon, il poursuit le processus d'insertion récursif.
  • La méthode « search() » recherche une valeur donnée dans l'arbre. Elle appelle la méthode « searchrecursive() » pour parcourir l'arbre de manière récursive et rechercher la valeur. Si la valeur est trouvée, elle renvoie le nœud correspondant. Si la valeur n'est pas trouvée ou si l'arbre est vide, il renvoie None.
  • Ensuite, nous créons une instance de BinarySearchTree appelée arbre. La méthode « insert () » insère plusieurs éléments dans l'arbre. Nous utilisons ensuite la méthode de recherche pour trouver des éléments spécifiques et afficher les résultats.
  • Lorsque nous appelons print(arbre.search(4)), il renvoie un objet Node qui représente le nœud contenant la valeur 4 dans l'arbre de recherche binaire. Étant donné qu'il n'existe pas de méthode str personnalisée définie pour la classe Node, la représentation de la chaîne par défaut est affichée.
 

Exercice 4:

Écrire un programme Python pour créer une classe représentant une structure de données de type pile. Inclure des méthodes pour insérer et retirer des éléments.

Solution:

# Définir une classe appelée Stack pour implémenter une structure de données de type pile.
class Stack:
    # Initialiser la pile avec une liste vide pour stocker les éléments
    def __init__(self):
        self.items = []

    # Insérer un élément dans la pile
    def push(self, item):
        self.items.append(item)

    # Retirer (enlever et renvoyer) un élément de la pile si celle-ci n'est pas vide
    def pop(self):
        if not self.is_empty():
            return self.items.pop()
        else:
            return "Impossible de supprimer de la pile vide."

    # Vérifier si la pile est vide
    def is_empty(self):
        return len(self.items) == 0

    # Récupérer le nombre d'éléments dans la pile
    def size(self):
        return len(self.items)

    # Regarder l'élément supérieur de la pile sans le retirer, si la pile n'est pas vide
    def peek(self):
        if not self.is_empty():
            return self.items[-1]
        else:
            return "Pile vide."


# Créer une instance de la classe Stack
pile = Stack()

# Ajouter des éléments à la pile
pile.push(0)
pile.push(1)
pile.push(2)
pile.push(3)
pile.push(4)

# Afficher la taille de la pile et l'élément supérieur
print("Taille de la pile:", pile.size())
print("Élément supérieur:", pile.peek())

# Retirer un élément de la pile et afficher l'élément retiré, ainsi que la taille et l'élément supérieur mis à jour.
removed_item = pile.pop()
print("\nÉlément retiré:", removed_item)
print("\nTaille de la pile:", pile.size())
print("Élément supérieur:", pile.peek())

Sortie:

Taille de la pile: 5
Élément supérieur: 4

Élément retiré: 4

Taille de la pile: 4
Élément supérieur: 3

Explication:

Dans l'exercice ci-dessus,

  • Nous définissons une classe « Stack » représentant une structure de données de type pile. Elle possède un attribut appelé « items », qui est initialement une liste vide.
  • La méthode « push() » prend un élément en argument et l'ajoute à la liste des éléments, le plaçant ainsi au sommet de la pile.
  • La méthode « pop() » retire et renvoie l'élément le plus haut de la pile. Elle vérifie que la pile est vide avant d'extraire un élément. Si la pile est vide, elle lève un IndexError avec un message d'erreur approprié.
  • La méthode « is_empty() » vérifie si la pile est vide en examinant la longueur de la liste des éléments.
  • La méthode « size() » renvoie le nombre d'éléments actuellement dans la pile en renvoyant la longueur de la liste des éléments.
  • La méthode « peek() » renvoie l'élément le plus haut de la pile sans le supprimer. Elle vérifie si la pile est vide avant d'y jeter un coup d'œil. Si la pile est vide, elle lève un IndexError avec un message d'erreur approprié.
  • Ensuite, nous créons une instance de la classe Stack appelée stack. Nous plaçons plusieurs éléments sur la pile à l'aide de la méthode push. Nous démontrons ensuite comment accéder à la taille de la pile à l'aide de la méthode size et jeter un coup d'œil à l'élément le plus haut à l'aide de la méthode « peek() ».
  • Nous démontrons également comment extraire un élément de la pile à l'aide de la méthode « pop() ».
 

Exercice 5:

Écrire un programme Python pour créer une classe représentant une structure de données de liste chaînée (linked list). Inclure des méthodes pour afficher les données d'une liste chaînée, insérer et supprimer des nœuds.

Solution:

# Définir une classe appelée Node pour représenter un nœud dans une liste chaînée
class Node:
    # Initialiser l'objet Node avec des données et mettre le pointeur suivant à None
    def __init__(self, data):
        self.data = data
        self.next = None

# Définir une classe appelée LinkedList pour représenter une liste chaînée.
class LinkedList:
    # Initialiser la liste chaînée avec un nœud de tête vide
    def __init__(self):
        self.head = None

    # Afficher les éléments de la liste chaînée
    def display(self):
        current = self.head
        while current:
            print(current.data, end=" ")
            current = current.next
        print()

    # Insérer un nouveau nœud avec les données fournies à la fin de la liste chaînée
    def insert(self, data):
        new_node = Node(data)
        if not self.head:
            self.head = new_node
        else:
            current = self.head
            while current.next:
                current = current.next
            current.next = new_node

    # Supprime de la liste chaînée un nœud contenant les données indiquées.
    def delete(self, data):
        if not self.head:
            return

        if self.head.data == data:
            self.head = self.head.next
            return

        current = self.head
        prev = None
        while current and current.data != data:
            prev = current
            current = current.next

        if current:
            prev.next = current.next


# Créer une instance de la classe LinkedList
liste = LinkedList()

# Insérer des éléments dans la liste chaînée
liste.insert(1)
liste.insert(2)
liste.insert(3)
liste.insert(4)
liste.insert(5)

# Afficher la liste chaînée initiale
print("Liste chaînée initiale:")
liste.display()

# Insérer un nouveau nœud contenant la valeur 6 dans la liste chaînée
liste.insert(6)
print("Après l'insertion d'un nouveau nœud (6):")
liste.display()

# Supprimer de la liste chaînée un nœud ayant pour valeur 2
liste.delete(2)
print("Après la suppression d'un nœud existant (2):")
liste.display() 

Sortie:

Liste chaînée initiale:
1 2 3 4 5 
Après l'insertion d'un nouveau nœud (6):
1 2 3 4 5 6 
Après la suppression d'un nœud existant (2):
1 3 4 5 6 

Explication:

Dans l'exercice ci-dessus,

  • Nous définissons une classe Node représentant un nœud dans la liste chaînée. Chaque nœud contient des données et une référence au nœud suivant (ou None s'il s'agit du dernier nœud).
  • La classe LinkedList représente la liste chaînée elle-même. Elle possède un attribut head qui pointe vers le premier nœud de la liste.
  • La méthode « display() » parcourt la liste chaînée à partir de la tête et affiche les données de chaque nœud.
  • La méthode « insert() » insère un nouveau nœud à la fin de la liste chaînée. Si la liste est vide (head est None), elle crée un nœud vide et le place en tête de liste.
  • La méthode « delete() » supprime de la liste chaînée la première occurrence d'un nœud contenant les données spécifiées. Elle gère séparément le cas où le nœud à supprimer est la tête.
  • Ensuite, nous créons une instance de la classe LinkedList appelée 'liste'. Nous insérons plusieurs nœuds dans la liste à l'aide de la méthode insert. La liste chaînée initiale est ensuite affichée à l'aide de la méthode display.
  • Nous démontrons l'insertion d'un nouveau nœud dans la liste ainsi que la suppression d'un nœud de la liste, puis nous affichons la liste mise à jour.
 

Exercice 6:

Écrire un programme Python pour créer une classe représentant une structure de données de file d'attente. Incluez des méthodes pour insérer des éléments dans la file d'attente et les retirer de la file d'attente.

Solution:

# Définir une classe appelée FileDAttente pour implémenter une structure de données de file d'attente.
class FileDAttente:
    # Initialiser la file d'attente avec une liste vide pour stocker les éléments
    def __init__(self):
        self.items = []

    # Ajouter un élément à la fin de la file d'attente
    def insert(self, item):
        self.items.append(item)

    # Retirer et renvoyer un élément du début de la file d'attente si celle-ci n'est pas vide
    def remove(self):
        if not self.is_empty():
            return self.items.pop(0)
        else:
            raise IndexError("Impossible de retirer d'une file d'attente vide.")

    # Vérifier si la file d'attente est vide
    def is_empty(self):
        return len(self.items) == 0


# Créer une instance de la classe FileDAttente
f = FileDAttente()

# Ajouter des éléments à la file d'attente
f.insert(6)
f.insert(1)
f.insert(3)
f.insert(5)
f.insert(8)

# Afficher les éléments actuels de la file d'attente
print("File d'attente actuelle:", f.items)

# Retirer les éléments du début de la file d'attente et afficher les éléments retirés de la file d'attente.
removed_item = f.remove()
print("Élément retiré de la file d'attente:", removed_item)
removed_item = f.remove()
print("Élément retiré de la file d'attente:", removed_item)

# Afficher les éléments mis à jour dans la file d'attente
print("File d'attente mise à jour:", f.items) 

Sortie:

File d'attente actuelle: [6, 1, 3, 5, 8]
Élément retiré de la file d'attente: 6
Élément retiré de la file d'attente: 1
File d'attente mise à jour: [3, 5, 8]

Explication:

Dans l'exercice ci-dessus,

  • Nous définissons une classe FileDAttente représentant une structure de données de file d'attente. Elle possède un attribut appelé items, qui est initialement une liste vide.
  • La méthode « insert() » prend un élément en argument et l'ajoute à la fin de la liste des éléments. Elle l'ajoute à la fin de la file d'attente.
  • La méthode « remove() » retire et renvoie l'élément au début de la file d'attente. Elle vérifie si la file d'attente est vide avant de retirer un élément de la file d'attente. Si la file d'attente est vide, elle lève un IndexError avec un message d'erreur approprié.
  • La méthode « is_empty() » vérifie si la file d'attente est vide en examinant la longueur de la liste des éléments.
  • Dans l'exemple d'utilisation, nous créons une instance de la classe FileDAttente appelée f. Nous mettons en file d'attente plusieurs éléments à l'aide de la méthode « insert() ».
  • De plus, nous démontrons comment retirer un élément de la file d'attente à l'aide de la méthode « remove ».
 

Éditeur de code Python: Testez votre code en ligne!


 

QCM Python

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *