NSI Terminale Program Objet
NSI Terminale Program Objet
NSI Terminale Program Objet
TD NSI - Algorithmique
Programmation Objet
Première partie
Cours - Programmation orientée objet
1 Introduction : Programmation procédurale, programmation orientée objet
1.1 La notion d’objet et de classe
— Jusqu’ici, les programmes ont été réalisés en programmation procédurales, c’est à dire que chaque programme a
été décomposé en plusieurs fonctions réalisant des tâches simples.
Cependant lorsque plusieurs programmeurs travaillent simultanément sur un projet, il est nécessaire de program-
mer autrement afin d’éviter les conflits entre les fonctions.
— Un objet se caractérise par 3 choses :
— son état
— son comportement
— son identité
L’état est défini par les valeurs des attributs de l’objet à un instant t.
Par exemple, pour un téléphone, certains attributs sont variables dans le temps comme allumé ou éteint, d’autres sont
invariants comme le modèle de téléphone.
Le comportement est défini par les méthodes de l’objet : en résumé, les méthodes définissent à quoi sert l’objet
et/ou permettent de modifier son état.
L’identité est définie à la déclaration de l’objet (instanciation) par le nom choisi, tout simplement.
— En programmation orientée objet, on fabrique de nouveau types de données correspondant aux besoin du pro-
gramme. On réfléchit alors aux caractéristiques des objets qui seront de ce type et aux actions possibles à partir de
ces objets.
Ces caractéristiques et ces actions sont regroupées dans un code spécifique associé au type de données, appelé
classe.
Une action possible sur les objets de type liste est le tri de celle-ci avec la méthode nommée sort().
On parle alors de méthode et la syntaxe est :
Classe
— Le type de données avec ses caractéristiques et ses actions possibles s’appelle classe.
— Les caractéristiques (ou variables) de la classe s’appellent les attributs.
— Les actions possibles à effectuer avec la classe s’appellent les méthodes.
— La classe définit donc les attributs et les actions possibles sur ces attributs, les méthodes.
— Un objet du type de la classe s’appelle une instance de la classe et la création d’un objet d’une
classe s’appelle une instanciation de cette classe.
— Lorsqu’on définit les attributs d’un objet de la classe, on parle d’instanciation.
— On dit que les attributs et les méthodes sont encapsulés dans la classe.
On retrouve les méthodes connues concernant les listes : sort(), count(), append(), pop() ...
Les autres méthodes encadrées par les underscores sont spéciales.
class Carte:
"Une carte d'un jeu de 32 ou 52 cartes"
def __init__(self,...):
Lorsque l’on créé un objet, son constructeur est appelé implicitement et l’ordinateur alloue de la mémoire pour
l’objet et ses attributs. On peut d’ailleurs obtenir l’adresse mémoire de notre objet créé x.
— Par ailleurs, l’obtention de la valeur d’un attribut d’un objet se fait par l’utilisation de l’opérateur d’accessibilité
point : nom_objet.nom_attribut
Cela peut se lire ainsi de droite à gauche nom_attribut appartenant à l’instance nom_objet
— La variable self.
self
La variable self , dans les méthodes d’un objet, désigne l’objet auquel s’appliquera la méthode.
Elle représente l’objet dans la méthode en attendant qu’il soit créé.
Dans cet exemple, la méthode __init__ (constructeur) est appelée implicitement. "self" fait référence à l’objet x
dans la première ligne et à l’objet y dans la seconde.
Encapsulation
— L’encapsulation désigne le principe de regrouper des données brutes avec un ensemble de
routines (méthodes) permettant de les lire ou de les manipuler.
— But de l’encapsulation : cacher la représentation interne des classes.
— pour simplifier la vie du programmeur qui les utilise ;
— pour masquer leur complexité (diviser pour régner) ;
— pour permettre de modifier celle-ci sans changer le reste du programme.
— la liste des méthodes devient une sorte de mode d’emploi de la classe.
Pour obtenir la valeur d’un attribut nous utiliserons la méthode des accesseurs (ou "getters") dont le nom est générale-
ment : getNom_attribut() . Par exemple ici :
Exercice 2.1
Créer deux autres méthodes permettant de récupérer la valeur de la carte et la couleur avec les "getters" (accesseurs) :
getCouleur() et getValeur().
2.3 Modifications contrôlées des valeurs des attributs : les mutateurs ou "setters"
On va devoir contrôler les valeurs attribuées aux attributs. Pour cela, on passe par des méthodes particulières appelées
mutateurs (ou "setters") qui vont modifier la valeur d’une propriété d’un objet.
Le nom d’un mutateur est généralement : setNom_attribut() .
Par exemple on va créer une carte c1, un 7 de coeur puis modifier sa valeur en la passant à 10.
Exercice 2.2
1. Créer le mutateur de l’attribut couleur sous la forme setCouleur(self,c) .
2. Créer une carte c2, un Roi de coeur puis modifier sa valeur en la passant à une Dame.
3. Modifier la couleur de la carte c2 en la passant à pique .
4. Modifier la carte c2 en la passant à 8 de carreau.
3 Premier bilan
Exemples :
4 Notion d’agrégation
La conception d’une classe a pour but généralement de pouvoir créer des objets qui suivent tous le même modèle de
fabrication.
Un objet dans la vraie vie, par exemple votre stylo, est composé d’autres objets : une pointe (ou plume), un réservoir
d’encre, éventuellement un capuchon et un ressort.... Votre stylo est ce qu’on appelle un objet agrégat et son réservoir
d’encre est donc un objet composant.
class Reservoir:
''' classe permettant de construire un réservoir d'encre
pour des stylos toutes marques, toutes dimensions '''
# Accesseur de self.couleur
def getCouleur(self):
return self.couleur
# Mutateur de self.couleur
def setCouleur(self, couleur):
self.couleur = couleur
class Stylo:
''' classe permettant de construire un stylo
avec un réservoir d'encre.
On ne s'occupe pas de ses autres caractérisques'''
pen = Stylo("Rouge")
print(pen.getCouleur())
# Changeons la cartouche d'encre
pen.setCouleur("Bleu")
Notez bien une chose : dans le fichier principal de votre programme, ici main.py, vous n’avez pas importé le fichier reser-
voir.py, vous n’avez même pas besoin de savoir qu’il existe et encore moins de savoir comment il est conçu. Et pourtant,
vous l’utilisez indirectement : en instanciant la classe Stylo, vous instanciez également la classe Reservoir. Et vous obte-
nez un objet stylo un peu plus complexe qu’il n’y parait.
Imaginez maintenant que vous vouliez un stylo quatre couleurs : oui, il vous faudra 4 instances de Reservoir dans Stylo.
Ce qui entraînera une modification des accesseurs et mutateurs. Et certainement une méthode de sélection de la couleur.
Les possibilités sont grandes.
Décomposition en fichiers
Cette architecture nécessite en général la création d’un fichier par classe. Elle permet de transformer
une classe sans toucher aux autres. Où tout simplement, de se partager le travail dans une équipe.
class JeuDeCartes:
def __init__(self,nombreCarte):
# Tous les attributs ne sont peut être pas représentés
self.nombreCarte=nombreCarte
self.paquetCarte=[]
...
# Accesseur de self.paquetCarte
def getPaquet(self):
...
Exercice 4.3
1. Quel est le type de self.paquetCarte ?
2. Dans quelle méthode instancie t’on la classe Carte ?
3. Que peut on ajouter à la classe JeuDeCartes pour empêcher de donner une valeur différente de 32 ou 52 à
l’attribut self.nombreCarte ?
4. Pourquoi est-ce important de faire cette vérification ?
5. Que pourrait on faire si la valeur passée dans le constructeur n’est pas correcte ?
6. Pourquoi la méthode creerPaquet() n’a pas besoin de paramètre autre que self ?
7. Quand utilise t’on la méthode creerPaquet() ?
8. Que manque t’il à ce code (en supposant les méthodes totalement définies) pour pouvoir être utilisé ? Faites
une analogie avec l’exemple du stylo.
9. Instancier la classe JeuDeCarte et utiliser successivement les méthodes melanger() et distribuerUneCarte()
Deuxième partie
TD - Programmation orientée objet
Exercice 1 : utilisation d’objet
On suppose écrite la classe Carte dont on vous donne les en-têtes de méthodes. Cette classe diffère légèrement de la
classe Carte vue plus haut, prenez le temps d’analyser ce code et de voir les différences :
class Carte:
def __init__(self, nom, couleur):
# Affectation de l'attribut nom et de l'attribut couleur
couleur = ('CARREAU', 'COEUR', 'TREFLE', 'PIQUE')
noms = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'Valet', 'Dame',
'Roi', 'As']
valeurs = {'2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9,
'10': 10, 'Valet': 11, 'Dame': 12, 'Roi': 13, 'As': 14}
def getNom(self):
# renvoie le nom de la carte (de la liste noms): Accesseur
def getCouleur(self):
# renvoie la couleur de la carte (de la liste couleur): Accesseur
def getValeur(self):
# renvoie la valeur de la carte (du dictionnaire valeurs) : Accesseur
# Mutateur
def setSurface(self,s): # s est un float,
...
class Appartement:
# nom est une string
def __init__(self,nom):
# L'objet est une liste de pièces (objets issus de la classe Piece)
self.listeDePieces=[]
self.nom=nom
def getNom(self):
# Accesseurs:
return self.nom
Écrire (sur feuille) un programme principal utilisant ces deux classes qui va :
1. créer une pièce « chambre1 » , de surface 20 m2 et une pièce « chambre2 » », de surface 15 m2 ,
2. créer une pièce « séjour » », de surface 25 m2 et une pièce « sdb » », de surface 10 m2 ,
3. créer une pièce « cuisine » », de surface 12 m2 ,
4. créer un appartement « appart205 » qui contiendra toutes les pièces créées,
5. afficher la surface totale de l’appartement créé.
6. afficher la liste des pièces et surfaces de l’appartement créé.
# Proposition expert:
# Dans l'éditeur PYTHON
class Piece:
# nom est une string et surface est un float
def __init__(self,nom,surface):
# chaque objet a pour attributs le nom de la pièce(string)
# et la surface de celle ci(float) en m2.
# on doit rentrer le couple nom de la pièce et la surface
# pour chaque pièce.
...
# Accesseurs: retournent les attributs d'un objet de cette classe
def getNom(self):
...
def getSurface(self):
...
# Mutateur: modifient les attributs, ici la surface d'une pièce déjà
# renseignée
def setSurface(self,s): # s est un float
...
class Appartement:
# nom est une string
def __init__(self,nom):
#nomme l'appartement et une liste de pièces vide à remplir
...
def ajouter(self,piece):
# ajoute une pièce (instance(=objet) de la classe Piece)
def nbPieces(self):
# retourne le nombre de pièces de l'appartement
...
def getSurfaceTotale(self):
# retourne la surface totale de l'appartement (un float)
...
def getListePieces(self): # retourne la liste des pièces
...
Consignes :
1. Écrire les méthodes constructeurs des deux classes.
En cas de difficulté, rendez vous à la version intermédiaire. (Différenciation)
2. Finaliser la classe Piece.
(a) Écrire les méthodes accesseurs et mutateurs de la classe Piece.
3. Finaliser la classe Appartement.
(a) Écrire la méthode qui permet d’ajouter une pièce(ajouter(self,piece)) de la liste de pièces présentes dans l’ap-
partement. (Rappel utile a)
(b) Écrire la méthode qui permet de retourner le nombre de pièces(nbPieces(self )) présentes dans l’appartement.
(Rappel utile b)
(c) Écrire la méthode getSurfaceTotale(self ), qui renvoie la surface totale de l’appartement. (Rappel utile b)
(d) Écrire la méthode getListePieces(self ), qui renvoie la liste des pièces de l’appartement.
4. Créer un tableau qui classe les méthodes de ces deux classes selon leur type : constructeur, accesseur, mutateur ou
autre.
Aide
Rappels utiles :
— (a) pour ajouter un élément à la fin d’une liste : nomDeListe.append(élément) ;
— (b) la longueur d’une listel s’obtient avec len(l).
Et devra retourner :
salon 21.3
appt25 [('chambre', 12.6), ('sdbToilettes', 7), ('cuisine', 7),
('salon', 21.3)]
nb pieces = 4 , Surface totale = 47.9
# Proposition intermédiaire:
# Dans l'éditeur PYTHON
class Piece:
# nom est une string et surface est un float
def __init__(self,nom,surface):
# chaque objet a pour attributs le nom de la pièce(string)
# et la surface de celle ci(float) en m2.
# on doit rentrer le couple nom de la pièce et la surface
# pour chaque pièce.
self.nom=nom
self.surface=surface
# Accesseurs: retournent les attributs d'un objet de cette classe
def getNom(self):
return self.surface
def getSurface(self):
...
# Mutateur: modifient les attributs, ici la surface d'une pièce
# déjà renseignée
def setSurface(self,s): # s est un float
...
class Appartement:
# nom est une string
def __init__(self,nom):
#nomme l'appartement et une liste de pièces vide à remplir
self.listeDePieces=[]
self.nom=nom
def ajouter(self,piece):
# ajoute une piece (instance(=objet) de la classe Piece)
def nbPieces(self):
# retourne le nombre de pièces de l'appartement
...
def getSurfaceTotale(self):
# retourne la surface totale de l'appartement (un float)
...
def getListePieces(self): # retourne la liste des pieces
...
Troisième partie
Corrections exercices du cours
Correction de l’exercice 2.1
Créer deux autres méthodes permettant de récupérer la valeur de la carte et la couleur avec les "getters" (accesseurs) :
getCouleur() et getValeur().
def getValeur(self):
return self.valeur
def getCouleur(self):
return self.valeur
def setCouleur(self,c):
self.couleur=c
2. Créer une carte c2, un Roi de coeur puis modifier sa valeur en la passant à une Dame.
Quatrième partie
Correction TD - Programmation orientée objet
Correction de l’exercice 1 : utilisation d’objet
1. Créer la carte Valet de COEUR que l’on nommera c1.
2. Afficher la valeur de c1.
3. Créer la carte As de PIQUE que l’on nommera c2.
4. Afficher la valeur de c2.
5. Modifier le nom de la carte c2 en Roi et afficher la valeur de c2.
6. Créer la carte 8 de TREFLE que l’on nommera c3.
7. Comparer les cartes c1 et c2 puis c1 et c3.
Ce qui donnerait :
Correction de l’exercice 3
class Piece:
def __init__(self,nom,surface):
self.nom=nom
self.surface=surface
def getSurface(self):
return self.surface
def getNom(self):
return self.nom
def setSurface(self,s):
self.surface=s
class Appartement:
def __init__(self,nom):
self.listeDePieces=[]
self.nom=nom
def getNom(self):
return self.nom
def ajouter(self,piece):
self.listeDePieces.append(piece)
def nbPieces(self):
return len(self.listeDePieces)
def getSurfaceTotale(self):
total=0
for piece in self.listeDePieces:
surf=piece.getSurface()
total=total+surf
return total
def getListePieces(self):
L=[]
for piece in self.listeDePieces:
surf=piece.getSurface()
nom=piece.getNom()
L.append((nom,surf))
return L
Tableau de classement des méthodes de ces deux classes selon leur type :
— constructeurs : les deux init
— accesseurs : Piece.getSurface(), Piece.getNom(), Appartement.getNom()
Appartement.getSurfaceTotale(), Appartemnt.getListePieces()
— mutateurs : Piece.setSurface(), Appartement.ajouter(),
— autre : Appartement.nbPieces() Et oui, nbPieces N’EST PAS un attribut de la classe Appartement, cette valeur n’est
stockée nulle part, elle est juste calculée par la méthode len de self.listeDePieces