Encapsulation
Lors de la définition d'une classe, il est possible de
restreindre voire d'interdire l'accès (aux objets des
autres classes) à des attributs ou méthodes des
instances de cette classe.
Lors de la déclaration d'attributs ou méthodes, on
précise leur utilisation :
privée : accessible uniquement depuis l’intérieur de la classe.
Règle d’écriture en Python : __att1, __m1(…), …
public : accessible par toutes les autres classes. Règle
d’écriture en Python : att1, m1(…), …
1
Encapsulation
Elément essentiel pour l’évolution des applications :
Tout ce qui est visible peut avoir été utilisé. Le changer peut
casser du code existant.
Tout ce qui est caché peut encore être changé.
Encapsulation :
ne pas permettre l'accès direct à tout dès que l'on a une
référence de l'objet
masquer les détails d'implémentation au programmeur client
modifier tout ce qui n'est pas public sans impact pour le
programmeur
2
Règles d’encapsulation :
Rendre privés les attributs caractérisant l‘état de l'objet : un
élément qui commence par deux soulignés représente une
information privée.
Fournir des méthodes publiques permettant d’accéder/
modifier l'attribut (accesseurs/mutateurs)
Mise en œuvre :
On commence par définir un attribut normal.
Si on a besoin de le contrôler, on passe à une propriété :
cette modification ne remet pas en cause le code client qui reste
inchangé
3
Propriétés
Définition d’une propriété :
class NomClasse :
def __init__(self, val, …)
self.__attr=val
…
@property
def attr(self):
…
@[Link]
def attr(self, valeur):
...
4
Exemple :
class Fichier : # Mutateur
"""Définition de la classe Fichier""" @[Link]
def nom(self, nom):
# Constructeur self.__nom=nom
def __init__(self, leNom , ext="txt" ) :
self.__nom = leNom # Autres méthodes
self.__extension=ext def nomEntier(self):
return self.__nom+"."+
# Accesseur self.__extension
@property
def nom(self): #Programme principal
return self.__nom fich= Fichier("MonFichier")
print([Link])
5
Sérialisation d’objets dans des fichiers
Avec le module pickle, il est possible d’enregistrer un
objet dans un fichier et de le récupérer par la suite.
Exemple :
import pickle
with open("lesPoints", 'wb') as f :
p= Point(2,3)
[Link](p,f)
with open("lesPoints", 'rb') as f :
p= [Link](f)
print(p)
6
Tri d’objets
Pour trier des séquences, Python propose deux
méthodes :
La méthode sort() de la classe list. Elle modifie la liste sur
laquelle elle s’applique.
La fonction de haut niveau sorted(). Elle prend une séquence
comme argument (set, list, tuple, dict) et elle renvoie une
nouvelle séquence triée.
Exemples :
maListe=["Pomme", "Banane", "Orange","Poire"]
[Link]() # maListe vaut ['Banane', 'Orange', 'Poire', 'Pomme']
maListe=[20, 15, 2, 16, 8]
maListeTriee= sorted(maListe) # maListeTriee vaut [2, 8, 15, 16, 20]
7
Python ne sait pas trier des séquences d’objets de type
défini par l’utilisateur
Les méthodes [Link]() et sorted() ont un pramètre
optionnel appelé key de type fonction.
La fonction à passer en argument prend un élément de
la liste et renvoie ce sur quoi doit ce faire le tri.
Exemples :
fruits=[("Pommes", 1.800, 50), ("Banane", 4.000, 25), ("Orange", 2.500, 30)]
[Link](key= lambda elment: elment[1])
# fruits vaut [('Pommes', 1.8, 50), ('Orange', 2.5, 30), ('Banane', 4.0, 25)]
8
Exemples (suite) :
class Etudiant :
def __init__(self, nom, age, moyenne):
[Link]=nom
[Link]=age
[Link]=moyenne
def __repr__(self) :
return [Link]
e1= Etudiant("Ali", 20, 13.40)
e2= Etudiant("Ahmed", 21,12.50)
e3= Etudiant("Salma", 20, 13.00)
liste=[e1, e2, e3]
[Link](key= lambda e : [Link], reverse=True)
print(liste) # [e2,e1,e3]
9
Les fonctions lambda ne sont pas le meilleur choix au
niveau rapidité, si l’on veut trier une liste contenant
beaucoup d’objets
Le module operator propose les
fonctions itemgetter() et attrgetter() qui peuvent être
très utiles en tant que fonction clés, si l’on veut trier une
liste de tuples ou d'objets selon un attribut ;
Exemple :
from operator import itemgetter
inventory = [(‘pomme', 3), ('banane', 2), ('orange', 1)]
sorted(inventory, key=itemgetter(0))
10
Exemple :
from operator import attrgetter
e1= Etudiant("Ali", 20, 13.00)
e2= Etudiant("Ahmed", 21,12.50)
e3= Etudiant("Salma", 22, 13.00)
e4= Etudiant("Kamel", 20, 13.00)
liste=[e1, e2, e3, e4]
listeTriee= sorted(liste, key=attrgetter("moyenne", "age"), reverse=True)
print (listeTriee) # [Salma, Ali, Kamel, Ahmed]
11
Héritage
Le principe d’héritage stipule que les caractéristiques
des classes supérieures sont héritées par les classes
dérivées.
Sa mise en œuvre consiste à mettre les connaissances
les plus générales en commun dans des classes qui
sont ensuite spécialisées par la définition de sous-
classes contenant des connaissances de plus en plus
spécifiques.
12
Héritage
La spécialisation d'une classe peut être réalisée selon
deux techniques :
L'enrichissement : la sous-classe est dotée de nouvelle(s)
méthode(s) et/ou de nouveau(x) attribut(s) ;
La redéfinition : une (ou plusieurs) méthode et/ou un attribut
hérité est redéfini.
13
Héritage
class Fichier : class FichierBinaire (Fichier) :
"""Définition de la classe """Définition de la classe
Fichier""" FichierBinaire"""
def __init__(self):
def __init__(self, enc):
self.__taille=0 Fichier.__init__(self)
self.__encodage=enc
def setTaille(self, taille) self.__taille= "0"
self.__taille=taille
def imprimer(self):
pass
def ouvrir(self):
print("Ouvrir le fichier") def ouvrir(self) :
print("Ouvrir fichier binaire")
14
Héritage et polymorphisme
L’héritage multiple consiste à faire hériter une classe de
plusieurs superclasses.
L'idée est de regrouper au sein d'une seule et même
classe les attributs et méthodes de plusieurs classes.
Python permet l’héritage multiple
Le polymorphisme signifie qu’à un même service
(d’une classe de base peuvent correspondre, dans les
classes dérivées, des méthodes différentes. Chaque
classe dérivée définit la forme (-morphe) sous laquelle
elle remplit le service (méthode).
15
Héritage et attributs protégés
Les attributs protégés sont les attributs d’une classe de
base qui ne sont visibles que des sous-classes. Règle
d’écriture en Python : _att1, _att2
En python, les attributs et méthodes protégées sont
accessibles normalement ; le préfixe a pour seul
objectif d'informer sur leur nature
16
Exceptions
Le principe des exceptions consiste à séparer la
détection d'une anomalie de son traitement.
Une exception est levée pour signaler une anomalie
lors de l'exécution d'une instruction.
Exemples d’exceptions en Python
10 / 0
ZeroDivisionError: division by zero
int('spam')
ValueError: invalid literal for int() with
base 10: 'spam'
17
Exceptions
d = { 'poires' : 5, 'pommes' : 7 }
d['oranges']
KeyError: 'oranges'
IndexError : Accès à un indice inexistant
TypeError : type d'argument incorrect
OSError : erreur provoquée par un appel système
NotImplementedError : erreur levée quand une méthode ne
possède pas d’implémentation
ValueError: invalid literal for int() with base 10: 'spam‘
…
18
Exceptions
Si une exception est levée dans une méthode, alors
l'exécution de la méthode s'arrête et on retourne
l'exception à l'appelant
L'appelant peut traiter l'anomalie génératrice de
l'exception si l'appel est fait dans un bloc try/except
try :
instruction1
instruction2
...
except Exception :
actions
19
Levée d’une exception
On peut forcer la levée d'une exception en utilisant
l'instruction raise
Exemple :
if a<0 :
raise Exception
20
Exceptions utilisateur
Les exceptions sont des objets.
On peut définir de nouvelles exceptions en spécialisant
la classe Exception
On utilise les exceptions afin de vérifier la bonne
utilisation des méthodes.
Exemple :
class ListeVide(Exception): else:
pass p=1
for i in liste :
def produit(liste:list)-> float: if i!=0 :
if not liste: p*=i
raise ListeVide return p
21
Traitement des exceptions
Chaque type d'exception peut avoir un traitement
différent
try :
instruction1
instruction2
...
except ExceptionType1 :
actions
except ExceptionType2 :
actions
finally :
actions à exécuter dans tous les cas (sauf sortie du programme)
22
Exceptions et objets
Exemple : vérifier que les paramètres d'entrée d'une
méthode ont les bons types et les bonnes valeurs
class NombreNegatif (Exception): #main
def __init__(self,message): try :
[Link]=message racineCarree(-1)
def racineCarree(n): except NombreNegatif as e :
if (n<0) : print([Link])
raise NombreNegatif("Pas de finally :
racine pour les nombres négatifs") print("C'est terminé")
else : print ("au revoir")
print(sqrt(n))
23
Gestion des exceptions
Exemple :
while True:
s = input('Entrez un entier : ')
try:
n = int(s)
print(n + 1)
break
except ValueError :
print("{} n'est pas un entier !".format(s))
24
Assertions
Les assertions sont un moyen de s’assurer, avant de
continuer, qu’une condition est respectée.
En général, on les utilise dans des blocs try … except
Syntaxe :
assert test
Si le test renvoie True, l’exécution se poursuit
normalement. Sinon, une exception AssertionError est
levée
25
Exemple
annee = input( "Saisissez une année : ")
try :
annee= int(annee)
assert annee>0
except ValueError :
print("Donnez un nombre!")
except AssertionError :
print("Donnez un nombre positif !")
26
Classes abstraites
Une classe abstraite est une classe qui ne peut pas
être instanciée
Les classes abstraite renforcent l'extensibilité des
programmes en factorisant des attributs et des
méthodes communs à différentes classes.
Pour obliger une classe fille d'une classe abstraite
d'implémenter les méthodes abstraites, on utilise le
module abc (Abstract Base Class) qui permet de
déclarer explicitement qu'une classe/ou une méthode
est abstraite.
27
Exemples :
from abc import ABC
class ObjetGeometrique(ABC):
@[Link]
def surface (self):
pass
geo= ObjetGeometrique()
TypeError : Can't instantiate abstract class ObjetGeometrique with abstract
methods surface
28
Exemple (suite) :
class Carre(ObjetGeometrique):
def __init__(self, cote):
[Link]=cote
def surface (self):
return cote**2
c= Carre(5)
print([Link]())
29
Itérateurs
La boucle
for i in obj :
permet de balayer tout objet obj itérable, c’est-à-dire
définissant la méthode __iter__(self)
__iter__(self ) doit renvoyer un itérateur définissant la
méthode __next__(self)
__next__(self) renvoie un objet (la valeur prise par i) et
modifie l’état de l’itérateur pour passer à l’élément
suivant.
L’exception StopIteration est levée si l’appel à
__next__( ) est impossible.
30
La boucle for est donc équivalente à:
it = obj.__iter__( )
try:
while True:
i = it.__next__()
...
except StopIteration:
pass
31
Exemple :
class UpTo: else:
def __init__(self,n): self.i = self.i + 1
self.n = n return self.i
self.i = 0 for i in UpTo(5):
def __iter__(self): print (i) # affiche 1,2,...,5
return self print(list(UpTo(5))) # [1, 2, 3, 4, 5]
def __next__(self):
if self.i == self.n:
raise StopIteration
32