Aller au contenu

Chapitre 1 - Entraînement : POO, modularité et tests


Écrire une classe Fraction avec :

  • un constructeur prenant un numérateur et un dénominateur ;
  • une méthode simplifier() qui simplifie la fraction (utiliser le PGCD) ;
  • les méthodes __str__, __add__ et __eq__.
>>> f1 = Fraction(2, 4)
>>> print(f1) # 1/2
>>> f2 = Fraction(1, 3)
>>> print(f1 + f2) # 5/6
Solution
from math import gcd
class Fraction:
def __init__(self, num, den):
assert den != 0, "Dénominateur nul"
d = gcd(abs(num), abs(den))
self.num = num // d
self.den = den // d
def __str__(self):
if self.den == 1:
return str(self.num)
return f"{self.num}/{self.den}"
def __add__(self, autre):
num = self.num * autre.den + autre.num * self.den
den = self.den * autre.den
return Fraction(num, den)
def __eq__(self, autre):
return self.num == autre.num and self.den == autre.den
f1 = Fraction(2, 4)
print(f1) # 1/2
f2 = Fraction(1, 3)
print(f1 + f2) # 5/6
print(Fraction(3, 6) == Fraction(1, 2)) # True

Pour chaque extrait de code, identifier le paradigme dominant (impératif, fonctionnel, objet) et justifier.

a.

notes = [12, 15, 8, 17, 14]
total = 0
for note in notes:
total += note
moyenne = total / len(notes)

b.

notes = [12, 15, 8, 17, 14]
bonnes_notes = list(filter(lambda n: n >= 14, notes))

c.

class Bulletin:
def __init__(self, eleve, notes):
self.eleve = eleve
self.notes = notes
def moyenne(self):
return sum(self.notes) / len(self.notes)
Solution

a. Paradigme impératif : variable accumulatrice total modifiée par une boucle for, instructions séquentielles.

b. Paradigme fonctionnel : utilisation de filter et lambda, pas de variable modifiée, transformation de données.

c. Paradigme objet : définition d'une classe avec attributs et méthodes, encapsulation des données.


Créer un module statistiques.py contenant les fonctions suivantes, documentées avec des docstrings :

  • moyenne(liste) : renvoie la moyenne d'une liste de nombres ;
  • ecart_type(liste) : renvoie l'écart-type ;
  • mediane(liste) : renvoie la médiane ;
  • quartiles(liste) : renvoie Q1 et Q3.

Le module doit pouvoir être testé directement (__name__ == "__main__").

Solution
"""Module de statistiques descriptives."""
def moyenne(liste):
"""Renvoie la moyenne d'une liste de nombres."""
assert len(liste) > 0, "La liste ne doit pas être vide"
return sum(liste) / len(liste)
def ecart_type(liste):
"""Renvoie l'écart-type d'une liste de nombres."""
moy = moyenne(liste)
variance = sum((x - moy) ** 2 for x in liste) / len(liste)
return variance ** 0.5
def mediane(liste):
"""Renvoie la médiane d'une liste de nombres."""
tri = sorted(liste)
n = len(tri)
if n % 2 == 1:
return tri[n // 2]
return (tri[n // 2 - 1] + tri[n // 2]) / 2
def quartiles(liste):
"""Renvoie (Q1, Q3) d'une liste de nombres."""
tri = sorted(liste)
n = len(tri)
q1 = mediane(tri[:n // 2])
q3 = mediane(tri[(n + 1) // 2:])
return (q1, q3)
if __name__ == "__main__":
donnees = [4, 7, 13, 2, 1, 9, 15, 12, 5, 8]
print(f"Moyenne : {moyenne(donnees):.2f}")
print(f"Écart-type : {ecart_type(donnees):.2f}")
print(f"Médiane : {mediane(donnees)}")
print(f"Quartiles : {quartiles(donnees)}")

Activité 1 - Même algorithme, trois paradigmes

Section intitulée « Activité 1 - Même algorithme, trois paradigmes »

Implémenter le crible d'Ératosthène (trouver tous les nombres premiers jusqu'à n) dans les trois paradigmes : impératif, fonctionnel et objet.

Solution

Impératif :

def crible_imperatif(n):
premiers = []
est_premier = [True] * (n + 1)
for i in range(2, n + 1):
if est_premier[i]:
premiers.append(i)
for j in range(i * i, n + 1, i):
est_premier[j] = False
return premiers

Fonctionnel :

def crible_fonctionnel(n):
def filtrer(nombres, p):
return [x for x in nombres if x == p or x % p != 0]
nombres = list(range(2, n + 1))
p = 2
while p * p <= n:
nombres = filtrer(nombres, p)
p = nombres[nombres.index(p) + 1] if p in nombres and nombres.index(p) + 1 < len(nombres) else n + 1
return nombres

Objet :

class Crible:
def __init__(self, n):
self.n = n
self.premiers = []
self._calculer()
def _calculer(self):
est_premier = [True] * (self.n + 1)
for i in range(2, self.n + 1):
if est_premier[i]:
self.premiers.append(i)
for j in range(i * i, self.n + 1, i):
est_premier[j] = False
def est_premier(self, k):
return k in self.premiers
def compter(self):
return len(self.premiers)