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 :

Mise en oeuvre de l'héritage en Python

Définition d'une classe de base : Person.py

L'héritage est un concept de programmation orientée objet qui permet de définir un type de données à partir d'un autre type de données qu'on va compléter. Je vous propose donc de commencer par coder une classe de base. Nous appellerons cette classe Person : elle permettra de représenter la notion de personne qui agrégera trois attributs (un prénom, un nom de famille et un email).

Vous noterez que j'y ai rajouté des propriétés permettant de valider les changements d'état. En cas d'incohérence, une exception de type PersonException. En fait, il y a déjà un lien d'héritage à ce niveau. Effectivement, cette classe dérive de BaseException (la classe de base de toutes les classes exceptions). Cette classe est fournie par l'environnement Python.

 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 
#!/usr/bin/python3

class PersonException( BaseException ):     # Un lien d'héritage !!!
    
    def __init__(self, message):
        super().__init__(message)


class Person( object ):
    
    def __init__(self, firstName="john", lastName="doe", email=None):
        self.firstName = firstName
        self.lastName = lastName
        self.email = email
        
        
    @property
    def firstName(self):
        return self.__firstName
    
    @firstName.setter
    def firstName(self, newFirstName):
        """A non-empty and non-null character string in lowercase.""" 
        if newFirstName is None:
            raise PersonException("firstName cannot be None")
        if not isinstance( newFirstName, str):
            raise PersonException("firstName must be a string")
        newFirstName = newFirstName.strip()
        if newFirstName == "":
            raise PersonException("firstName cannot be empty")
        self.__firstName = newFirstName.lower()
        
        
    @property
    def lastName(self):
        return self.__lastName
    
    @lastName.setter
    def lastName(self, newLastName):
        """A non-empty and non-null character string in uppercase.""" 
        if newLastName is None:
            raise PersonException("lastName cannot be None")
        if not isinstance( newLastName, str):
            raise PersonException("lastName must be a string")
        newLastName = newLastName.strip()
        if newLastName == "":
            raise PersonException("lastName cannot be empty")
        self.__lastName = newLastName.upper()
        
        
    @property
    def email(self):
        return self.__email
    
    @email.setter
    def email(self, newEmail):
        """A non-empty character string or None value.""" 
        if not newEmail is None:
            if not isinstance( newEmail, str):
                raise PersonException("lastName must be a string")
            newEmail = newEmail.strip()
            if newEmail == "":
                raise PersonException("lastName cannot be empty")
        self.__email = newEmail
        
        
    def __str__(self):
        mail = "-" if self.email is None else self.email
        return "%s %s - %s" % (self.firstName, self.lastName, mail)
Fichier Person.py

Définition d'une classe dérivée : Employee.py

Maintenance nous pouvons dériver une classe Employee de la classe Person. Notez, dans le constructeur et dans la méthode __str__, la présence de super() qui permet de rappeler les méthodes de même noms, mais qui sont définies dans la classe parente (la super-classe).

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
#!/usr/bin/python3

from Person import Person, PersonException

class Employee( Person ):
    
    def __init__(self, firstName="john", lastName="doe", email=None, salary = 0):
        super().__init__(firstName, lastName, email)
        self.salary = salary
        
    @property
    def salary(self):
        return self.__salary
    
    @salary.setter
    def salary(self, newSalary):
        if not isinstance(newSalary, float) and not isinstance(newSalary, int):
            raise PersonException("salary must be a numeric value")
        if newSalary < 0:
            raise PersonException("a salary must be positive or zero")
        self.__salary = newSalary
       
    def __str__(self):
        return "%s == %.2f euros" % (super().__str__(), self.salary)
Fichier Employee.py

Bien tester cette classe

Afin de bien tester notre programme, 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 
 33 
 34 
 35 
import unittest

from Person import PersonException
from Employee import Employee

class TestCase(unittest.TestCase):

    def testGoodProperties(self):
        zorro = Employee( "Zorro", "De La Vega   ", None, 2000 )
        
        self.assertEqual("zorro", zorro.firstName)
        self.assertEqual("DE LA VEGA", zorro.lastName)
        self.assertIsNone(zorro.email)
        self.assertEqual(2000, zorro.salary)

    def testBadFirstName(self):
        with self.assertRaises(PersonException):
            Employee("", "Doe", None, 0)

    def testBadLastName(self):
        with self.assertRaises(PersonException):
            Employee("John", None, None, 0)

    def testBadEmail(self):
        with self.assertRaises(PersonException):
            Employee("toto", "Doe", 10, 0)

    def testBadSalary(self):
        with self.assertRaises(PersonException):
            Employee("John", "Doe", None, -1000)


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