Participer au site avec un Tip
Rechercher
 

Améliorations / Corrections

Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.

Emplacement :

Description des améliorations :

Exemple de définition d'une classe en Python

Python est un langage de programmation orienté objet. Il est donc possible de définir des nouveaux types de données par le biais de classes. Pour de plus amples informations sur la programmation orientée objet en Python, je vous renvoie vers les tutoriels/cours associés.

Exemple de code

L'exemple ci-dessous défini un nouveau type de données de manipulation de nombres rationnels (de fractions). On peut par exemple imaginer le rationnel 3/5 qui est constitué d'un numérateur, fixé à la valeur 3, et d'un dénominateur, qui lui est fixé à la valeur 5. Pour rappel, mathématiquement parlant, il est interdit de mettre un dénominateur à 0. L'objectif principal de la classe est de vérifier les changements d'états sur vos nombres rationnels afin de garantir qu'un objet ne soit jamais mis dans un état incohérent. Au pire, on déclenche une exception (une erreur). Pour réaliser ces contrôles, la classe utilise le concept de propriétés (repérable dans le code via les décorateurs Python, introduit par le caractère @).

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
 37 
 38 
 39 
 40 
 41 
 42 
 43 
 44 
 45 
 46 
 47 
 48 
 49 
 50 
 51 
 52 
 53 
 54 
 55 
 56 
 57 
 58 
 59 
 60 
 61 
 62 
 63 
 64 
 65 
 66 
 67 
 68 
 69 
 70 
 71 
 72 
 73 
 74 
 75 
 76 
 77 
 78 
 79 
 80 
 81 
 82 
 83 
 84 
 85 
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import math


class Rational(object):    

    def __init__(self, num: int=0, den: int=1):
        self.numerator = num
        self.denominator = den
        self.simplify()        
    
    
    @property
    def numerator(self):
        return self.__numerator
    
     
    @numerator.setter 
    def numerator(self, newNum):
        if not isinstance(newNum, int):
            raise TypeError("Numerator must be an integer")
        self.__numerator = newNum
         
         
    @property
    def denominator(self):
        return self.__denominator
    
    
    @denominator.setter 
    def denominator(self, newDen):
        if not isinstance(newDen, int):
            raise TypeError("Denominator must be an integer")
        if newDen == 0:
            raise ValueError("Denominator cannot be zero")
        self.__denominator = newDen
    
         
    def simplify(self): 
        pgcd = math.gcd(self.__numerator, self.__denominator)
        self.__numerator //= pgcd       # Division entière 
        self.__denominator //= pgcd 
            
            
    def __str__(self):  
        return f"[{self.__numerator}/{self.__denominator}]"
    
    
    def __add__(self, r2):
        return Rational(
            self.numerator*r2.denominator + self.denominator*r2.numerator,
            self.denominator * r2.denominator
        )

    # Ajouter les méthodes  __sub__    __mul__   __truediv__
    
    
    def __lt__(self, r2):
        return self.numerator * r2.denominator < self.denominator * r2.numerator

    # Ajouter les méthodes   __le__   __gt__   __ge__   __eq__   __ne__ 
    
    def to_float(self):
        return self.__numerator / self.__denominator
            
    
if __name__ == '__main__':
    r1 = Rational(1, 2)    
    r2 = Rational(4,1)    
    r = r1 + r2
    print(r1, "+", r2, "=", r)
    
    to_simplify = Rational(100, 50)
    print("[100,50] ==", to_simplify)

    r = Rational()
    r.numerator = 33;
    r.denominator = 44;
    print("Prop: %s" % str(r))
    
    try: 
        bad = Rational(0, 0)
    except ValueError as e:
        print("An error is raised")
Exemple de définition d'une classe Python de manipulation de fraction

Pour lancer cet exemple, veuillez procéder ainsi :

$> python Rational.py 
[1/2] + [4/1] == [9/2]
[100,50] == [2/1]
Prop: [33/44]
An error is raised
$>

Bien tester cette classe

Afin de bien tester cette classe, je vous propose de mettre en place une petite batterie de test unittest.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
import unittest

from Rational import Rational

class Test(unittest.TestCase):

    def setUp(self):
        print( "Avant chaque test" )

    def tearDown(self):
        print( "Après chaque test" )

    def testSimplify(self):
        r1 = Rational( 2*3*5*7*11, 3*5*7*13 )
        assert r1.numerator == 22
        assert r1.denominator == 13

    def testAddition(self):
        r1 = Rational(1,3)
        r2 = Rational(2,1)
        result = r1 + r2
        assert result.numerator == 7
        assert result.denominator == 3

    @unittest.expectedFailure
    def testBadDenominator(self):
        Rational( 1, 0 )
        

if __name__ == "__main__":
    #import sys;sys.argv = ['', 'Test.testName']
    unittest.main()
Quelques tests de notre classe via unittest

Une fois la classe de test codée, si vous utilisez l'IDE PyDev, cliquez avec le bouton droit de la souris sur le fichier de test (dans l'explorateur de projets). Sélectionnez-y "Run As", puis "Python Run". Cela lance le framework unittest. Une nouvelle vue (une nouvelle fenêtre) devrait s'ouvrir et afficher les résultats de votre batterie de tests. En voici une capture d'écran.

Unittest results