Lab 5 : Orienté objet en Python

Nous amuser avec de véritables classes, en écrivant une bonne partie du code et en créant plusieurs classes pour résoudre divers problèmes.

Enseignement à Evry

Classe de base

Créer une classe pour représenter les cours à Evry. Copiez ce qui suit dans un fichier et enregistrez-le sous le nom cours.py.

classe EvryCours :
    def __init__(self, departement, filiere, semestre, titre) :
        self.department = departement
        self.filiere = filiere
        self.semestre = semestre
        self.titre = titre

Vous pouvez supposer que tous les arguments présentés à ce constructeur seront des chaînes de caractères.

Nous pouvons importer cette définition de classe et créer une instance de la classe dans l'interpréteur interactif, en exécutant :

$ python3
>>> from cours import EvryCours
>>> evry_python = EvryCours("Inf", "L3ASR", "S5" "Langage Script")

Nous pouvons accéder aux attributs de evry_python, notre objet d'instance :

>>> from cours import EvryCours
>>> evry_python = EvryCours("Inf", "L3ASR", "S5", "Langage Script")
>>> evry_python.titre
Langage Script
>>> evry_python.filiere
L3ASR
>>>

Héritage

Pendant le confinement à cause du Covid, nous avons besoins de faire des cours en ligne. Ajoutons l'héritage en créant une classe EvryCoursEnligne qui prend un paramètre supplémentaire enregistrement dont la valeur par défaut est False.

Écrivez le code suivant dans le fichier cours.py :

classe EvryCoursEnligne(EvryCours) :
    def __init__(self, department, filiere, semestre, titre, enregistrement=False) :
        super().__init__(department, filiere, semestre, titre)
        self.est_enregistre = enregistrement

L'appel super() est un peu magique - il construit un objet décrit par la superclasse, ce qui nous permet d'appeler la méthode __init__ sur cet objet.

Exécuter les lignes suivantes dans votre terminal.

>>> from cours import EvryCours, EvryCoursEnligne
>>> a = EvryCours("Inf", "L3I", "S5", "Réseaux")
>>> b = EvryCours("Inf", "L3ASR", "S5", "Langage Script")
>>> x = EvryCoursEnligne("Inf", "L3I", "S5", "Introduction à l'algorithmique", enregistrement=True)
>>> a.filiere
"L3I"
>>> b.filiere
"L3ASR"

Quel est le résultat le code ci-dessous ?

type(a)
isinstance(a, EvryCours)
isinstance(b, EvryCours)
isinstance(x, EvryCours)
isinstance(x, EvryCoursEnligne)
type(a) == type(b)
type(b) == type(x)
a == b
b == x

Attributs supplémentaires

Ajoutons plus de fonctionnalités à la classe EvryCours.

Mise en œuvre des conditions préalables

Maintenant, nous allons nous concentrer sur EvryCours. Nous voulons mettre en place une fonctionnalité permettant de déterminer si un cours d'informatique est un préalable à un autre. Dans notre implémentation, nous supposerons que l'ordre des cours est simplement déterminé par la partie numérique du semestre du cours : par exemple, S5 vient avant S6. Après l'implémentation, vous devriez être en mesure de voir :

>>> from cours import EvryCours, EvryCoursEnligne
>>> a = EvryCours("Inf", "L3I", "S5", "Réseaux")
>>> b = EvryCours("Inf", "L3ASR", "S5", "Langage Script")
>>> x = EvryCoursEnligne("Inf", "L3I", "S5", "Introduction à l'algorithmique", enregistrement=True)
>>> y = EvryCoursEnligne("Inf", "L3I", "S6", "Algorithmique des graphes", enregistrement=True)
>>> y > x
Vrai
>>> a > b
Faux

Pour ce faire, vous devrez mettre en œuvre une méthode magique __le__ qui ajoutera une fonctionnalité permettant de déterminer si un cours est un préalable à un autre cours. Consultez le site total ordering pour savoir ce que __le__ doit retourner en fonction de l'argument que vous avez fourni.

Pour donner quelques conseils sur la façon d'ajouter cette fonctionnalité, voyez comment vous pouvez extraire le numéro int réel de l'attribut du semestre du cours.

De plus, vous devriez implémenter un __eq__ dans EvryCours. Deux cours sont indépendantes si elles sont dans le même département et le même semestre.

Héritage

Considérer le code suivant:

class Transportation:
    roues = 0

    def __init__(self):
        self.roues = -1

    def travel_one(self):
        print("Voyager en transport générique")

    def travel(self, distance):
        for _ in range(distance):
            self.travel_one()

    def is_auto(self):
        return self.roues == 4

class Bike(Transportation):

    def travel_one(self):
        print("Faire du vélo 1km")

class Car(Transportation):
    roues = 4

    def travel_one(self):
        print("Conduire 1 km")

    def make_sound(self):
        print("VROOM")

class Ferrari(Car):
    pass

t = Transportation()
b = Bike()
c = Car()
f = Ferrari()

Prédire la sortie du code ci-dessous.

isinstance(t, Transportation)

isinstance(b, Bike)
isinstance(b, Transportation)
isinstance(b, Car)
isinstance(b, t)

isinstance(c, Car)
isinstance(c, Transportation)

isinstance(f, Ferrari)
isinstance(f, Car)
isinstance(f, Transportation)

issubclass(Bike, Transportation)
issubclass(Car, Transportation)
issubclass(Ferrari, Car)
issubclass(Ferrari, Transportation)
issubclass(Transportation, Transportation)

b.travel(5)
c.is_auto()
f.is_auto()
b.is_auto()
b.make_sound()
c.travel(10)
f.travel(4)

Fractions

Nous allons implémenter une classe fraction pour gérér les nombres fractionnaires. Les attributs de la classe seront le numérateur et le dénominateur. Compléter le code suivant.

class fraction
    # un constructeur
    def __init__(???): pass
    
    # simplifier le nombre s'il ne l'est pas
    def simplify(???): pass

    # évaluer sa valeur 
    def eval(???): pass
    
    # convertir en string
    def __str__(???): pass
    
    # opérations
    def __add__(???): pass
    
    def __sub__(???): pass
    
    def __mult__(???): pass

Le résultat souhaitable doit être comme suit.

a = fraction(4,8)
b = fraction(4,5)
print(a, "*", b, "=", a*b) # doit afficher 2/5
print(a, "+", b, "=", a+b) # doit afficher 13/10

Polynômes d'ordre 2

Construire une classe polynome gérant les polynômes d'ordre 2. On souhaite les comportements comme ci-dessous.

p = polynome(2, 1, 2)
q = polynome(1, 0, 1)

print(p) # doit afficher 2x^2+x+2
print(q) # doit afficher x^2+1

print(p.eval(0)) # doit afficher 2
print(p+q) # doit afficher 3x^2+x+3
print(q*5) # doit afficher 5x^2+5

Ajouter une méthode calculant les racines d'un polynôme.