Programmation orientée objet (TD)

1.5. Programmation orientée objet (TD)#

1.5.1. Pour commencer#

Exercise 1.1

  1. Écrire une classe Eleve qui contiendra les attributs nom, classe et note.

  2. Instancier trois élèves de cette classe.

  3. Écrire une fonction compare(eleve1, eleve2) qui renvoie le nom de l’élève ayant la meilleur note.

  4. Écrire la méthode __eq__ qui renvoie True si les élèves ont la même note et False sinon.

Exercise 1.2

Écrire une classe Player qui :

  1. ne prendra aucun argument lors de son instanciation.

  2. affectera à chaque objet créé un attribut energie valant 3 par défaut.

  3. affectera à chaque objet créé un attribut alive valant True par défaut.

  4. fournira à chaque objet une méthode blessure() qui diminue l’attribut energie de 1.

  5. fournira à chaque objet une méthode soin() qui augmente l’attribut energie de 1.

  6. si l’attribut energie passe à 0, l’attribut alive doit passer à False et ne doit plus pouvoir évoluer.

1.5.2. TD sur les fractions#

Le but de ce Travail Dirigé est de prendre en main la réalisation d’une classe et l’utiliser en tant qu’objet. Le T.D. se focalise donc sur cet aspect, même si d’autres aspects peuvent être travaillés.

Le travail doit être déposé avant demain dans le dépot suivant

Avertissement

Attention, une fois passé la date de demain soir, ce dépot ne sera plus accessible. Votre fichier doit être au format Notebook (*.ipynb), nommé suivant le schéma : <date (format aaad-mm-jj)> <nom> <prenom> <titre du TP>

Exercise 1.3

Rédiger une classe Fraction permettant de

  1. créer un objet Fraction à partir de son numérateur et dénominateur ;

  2. tester si deux fractions sont égales avec

    f = Fraction(2,3)
    g = Fraction(4,6)
    assert f.egal(g) == True
    
  3. additionner deux fractions

    f = Fraction(2,3)
    g = Fraction(4,5)
    h = f.somme(g)
    assert h.egal(Fraction(22,15)) == True
    
  4. soustraire deux fractions

  5. multiplier deux fractions

  6. prendre l’inverse d’une fraction

  7. diviser deux fractions

  8. donner le numérateur et le dénominateur

  9. simplier une fraction (peut être une fonction en dehors de la classe)

On veillera à commenter ses fonctions, à donner des indications de types et à tester les entrées sorties sur des exemples simples.

def somme(a: float, b:float) -> float
    """Renvoie la somme de deux float
    
    Une bête addition.
    
    Args:
        a (float): Le premier opérande
        b (float): Le deuxième opérande
    
    Returns:
        float: la somme
        
    Exemples:
    >>> somme(2.2, 5.3)
    7.5
    """
    return a+b

assert somme(2.2, 5.3) == 7.5

Astuce

Note

Si la docstring contient >>> fonction(args) suivi du résultat attendu, on peut placer

%%doctest
from doctest import testmod
testmod(verbose=True)

dans le Notebook Jupyter pour tester la fonction.

Hide code cell content
from IPython.display import Code
Hide code cell content
Code(filename='fraction.py',language='python3')
"""
fraction.py

une classe (incomplète) Fraction
une fonction egyptian donnant la decomposition égyptienne d'une fraction

Auteur  : S. Hoarau
Date    : 2021-09-19
Licence : CC BY-NC-SA 4.0 http://creativecommons.org/licenses/by-nc-sa/4.0/
"""
import math

class Fraction:
    
    PRECISION = 0.0000001
    
    def __init__(self, num, den):
        if den:
            self.__den = den
        else:
            raise ZeroDivisionError("denominator can't be zero")
        self.__num = num
        
    @property
    def num(self):
        return self.__num
    
    @num.setter
    def num(self, num):
        self.__num = num
        
    @property
    def den(self):
        return self.__den
    
    @den.setter
    def den(self, den):
        if den:
            self.__den = den
        else:
            raise ZeroDivisionError("denominator can't be zero")
    
    @staticmethod
    def reduce(a, b):
        pgcd = math.gcd(a, b)
        return a//pgcd, b//pgcd
    
    @classmethod
    def float(cls, f):
        if isinstance(f, float):
            den = 1
            while abs(int(f) - f) > Fraction.PRECISION:
                den *= 10
                f *= 10
            return Fraction(*Fraction.reduce(int(f), den))
        else:
            raise TypeError(f"{repr(f)} must be a float")
        
    def __str__(self):
        if self.den == 1:
            return str(self.num)
        else:
            return f'{self.num}/{self.den}'
    
    def __repr__(self):
        return f'Fraction({self.num}, {self.den})'
    
    def __eq__(self, f):
        if isinstance(f, int) or isinstance(f, float):
            return self.num % self.den == 0 and self.num // self.den == f
        elif isinstance(f, Fraction):
            return self.num * f.den == f.num * self.den
        return False
    
    def __lt__(self, f):
        if isinstance(f, int) or isinstance(f, float):
            return self.num / self.den < f
        elif isinstance(f, Fraction):
            return self.num * f.den < f.num * self.den
        else:
            raise NotImplemented(f"can't compare {repr(self)} and {repr(f)}")
    
    def __gt__(self, f):
        if isinstance(f, int) or isinstance(f, float):
            return self.num / self.den > f
        elif isinstance(f, Fraction):
            return self.num * f.den > f.num * self.den
        else:
            raise NotImplemented(f"can't compare {repr(self)} and {repr(f)}")
    
    def __add__(self, f):
        if isinstance(f, Fraction):
            num, den = Fraction.reduce(self.num * f.den + f.num * self.den, self.den * f.den)
            return Fraction(num, den)
        elif isinstance(f, int):
            num, den = Fraction.reduce(self.num + self.den * f, self.den)
            return Fraction(num, den)
        elif isinstance(f, float):
            return self.__add__(Fraction.float(f))

    def __sub__(self, f):
        if isinstance(f, Fraction):
            num, den = Fraction.reduce(self.num * f.den - f.num * self.den, self.den * f.den)
            return Fraction(num, den)
        elif isinstance(f, int):
            num, den = Fraction.reduce(self.num - self.den * f, self.den)
            return Fraction(num, den)
        elif isinstance(f, float):
            return self.__sub__(Fraction.float(f))
    
    def __mul__(self, f):
        if isinstance(f, Fraction):
            num, den = Fraction.reduce(self.num * f.num, self.den * f.den)
            return Fraction(num, den)
        elif isinstance(f, int):
            num, den = Fraction.reduce(self.num * f, self.den)
            return Fraction(num, den)
        elif isinstance(f, float):
            return self.__mul__(Fraction.float(f))        
        
        
    def simplify(self):
        num, den = Fraction.reduce(self.num, self.den)
        return Fraction(num, den)
    
    def auto_simplify(self):
        self.num, self.den = Fraction.reduce(self.num, self.den)


def egyptian(f):
    if isinstance(f, Fraction):
        if f < 1:
            reste = f.simplify()
            decompo = []
            n = 2
            while reste != 0:
                unit_frac = Fraction(1, n)
                while reste < unit_frac:
                    n += 1
                    unit_frac = Fraction(1, n)
                decompo.append(unit_frac)
                reste -= unit_frac
            return decompo
        else:
            raise ValueError(f"{f} is greater than 1 and has no egyptian decomposition")
    else:
        raise TypeError('Only Fraction smaller than 1 has egyptian decomposition')