POO, documentation et tests - TP6
1 Créer l’arborscence
└── P
└── Cours1A
└── IPOO
├── TP1
│ ├── Exercice_1
│ │ └── ex.py
│ ├── Exercice_2
│ │ └── ex.py
│ ├── ...
│ └── Exercice_7
│ └── ex.py
├── TP2
│ ├── Exercice_1
│ │ └── ex.py
│ ├── Exercice_2
│ ├── ...
Pour prendre la bonne habitude de bien ranger vos fichiers, vous allez créer l’arborscence ci-dessus. Vous pouvez créer chaque dossier et fichier à la main, ou utiliser les commandes ci-dessous (mkdir : make directory):
-
- Sur le bureau > clic droit > Git Bash here
-
mkdir -p /p/Cours1A/IPOO/TP6/Exercice_{1..3}/- dans Git Bash : clic droit > Paste ou MAJ + INSER
Il est important de stocker vos fichiers dans votre lecteur P: et pas sur votre bureau ou votre disque C: car vos fichiers risqueraient de disparaitre !
2 Moodle
3 Rappels
3.1 Lancer les tests
Plusieurs possibilités :
- Coller ceci en bas de votre classe, puis cliquer sur l’icone éxéctuer ▶️
if __name__ == '__main__':
import doctest
doctest.testmod(verbose=True)- dans un terminal :
python -m pytest --doctest-modules - utiliser l’interface de VSCode (à gauche icone Testing en forme de fiole triangulaire)
3.2 Attributs privés
En rendant les attributs de classe privés, vous pouvez contrôler strictement l’accès à ces attributs.
Vous pouvez fournir des méthodes spécifiques : “getter” et “setter”, pour manipuler ces attributs de manière contrôlée et sûre.
Exemple :
Avec un attribut public, aucun controle n’est effectué sur prix.
Il est alors possible à l’extérieur de l’objet de :
- obtenir sa valeur
- modifier sa valeur, et même son type
article.py
class Article:
def __init__(self, prix):
self.prix = prixmain.py
a = Article(5)
a.prix = "toto"
a.prix = True
print(a.prix)
# TrueAvec un attribut privé, il est possible de mettre en place des controles
article.py
class Article:
def __init__(self, prix):
self.__prix = prix
def obtenir_prix(self):
'''Getter'''
return self.__prix
def modifier_prix(self, new_prix):
'''Setter'''
if isinstance(new_prix, int) and new_prix > 0:
self.__prix = new_prixmain.py
a = Article(5)
# print(a.__prix)
# 'Article' object has no attribute '__prix'
a.modifier_prix(10)
print(a.obtenir_prix())
# 10Quand vous déclarez un attribut privé dans votre constructeur, Python va renommer votre attribut en ajoutant un préfixe _ClassName
Dans l’exemple ci-dessus, l’attribut __prix deviendra _Article__prix.
a = Article(5)
print(a._Article__prix)
# 5Si vous tentez de modifier l’attribut __prix, cela va en fait créer un nouvel attribut
a = Article(5)
a.__prix = 10
print(a.__prix)
# 10
print(a._Article__prix)
# 5| Code UML | Préfixe Python | Description | |
|---|---|---|---|
| Public | + |
Par défaut, tous les attributs et méthodes dans une classe Python sont considérés comme publics. Cela signifie qu’ils peuvent être accédés depuis l’extérieur de la classe. | |
| Privé | - |
__ |
Pas natif en Python. Il ne peut être accédé qu’à l’intérieur de la classe elle-même. |
| Protected | # |
_ |
Pas natif en Python. Seules la classe possédant l’élément et les classes filles peuvent y accéder. |
3.3 Héritage et classes abstraites
Une classe abstraite ne peut pas être instanciée, c’est à dire qu’on ne peut pas créer d’objets de cette classe.
L’intérêt est de fournir un socle commun à des classes filles.
Exemple :
- les voitures et les vélos ont des attributs et méthodes communes
- tout ce qui leur est commun est codé dans la classe
Vehiculedont ils héritent - ce qui les différencie est codé dans leurs propres classes
- la partie commune du constructeur est codé dans la classe mère
- la méthode accelerer() est déclarée abstraite dans la classe mère
- ce qui veut dire que toutes les classes filles devront redéfinir cette méthode
from abc import ABC, abstractmethod
class Vehicule(ABC):
def __init__(self, nb_roues):
self.nb_roues = nb_roues
self.vitesse = 0
@abstractmethod
def accelerer(self):
pass
class Voiture(Vehicule):
def __init__(self, marque, nb_roues):
super().__init__(nb_roues=4)
self.marque = marque
def accelerer(self):
self.vitesse += 20
class Velo(Vehicule):
def __init__(self, porte_bagages, nb_roues):
super().__init__(nb_roues=2)
self.porte_bagages = porte_bagages
def accelerer(self):
self.vitesse += 54 Exercices
4.1 Exercice 1
-
-
- dans votre Explorer à gauche apparait l’arborescence des dossiers et fichiers de Exercice_1
-
-
- attributs publics : arguments des constructeurs des classes
- attributs protégés : initialisés dans les constructeurs
4.2 Exercice 2
Dans les constructeurs, vérifier tous les types
def __init__(self, nom) if not isinstance(nom, str): raise TypeError("Le nom doit être une chaîne de caractères.") self.nom = nom-
from aeroport import Aeroport
4.3 Exercice 3
- une classe abstraite hérite de ABC
- une méthode abstraite est précédée par le décorateur @abstractmethod
- le mot clé
super()permet de faire référence à la classe mère
from abc import ABC, abstractmethod5 Template classe
class MaClasse:
'''titre_ma_classe
Description
Attributes
----------
attribut_1 : type_attribut_1 (str, int, float, list, bool, function...)
desc_attribut_1
attribut_2 : type_attribut_2
desc_attribut_2.
Valeur par défaut : False
attribut_3 : type_attribut_3
desc_attribut_3. Initialisé à 0
'''
def __init__(self, parametre_1, parametre_2):
'''Constructeur de l'objet
Parameters
----------
parametre_1 : type_parametre_1
desc_parametre_1
parametre_2 : type_parametre_2
desc_parametre_2
'''
self.attribut_1 = parametre_1
self.attribut_2 = parametre_2
self.attribut_3 = 0
def ma_methode(self, param1):
'''desc_courte_ma_methode
desc_longue_ma_methode_facultatif
Parameters
----------
param1 : type
desc_param_1
Returns
-------
type
desc_retour
Examples
--------
>>> mon_obj = ma_classe("toto")
>>> mon_obj.ma_methode("xxx")
2
'''
return 2
def __str__(self):
'''Conversion de l'objet en chaîne de caractères
Examples
--------
>>> mon_obj = ma_classe("toto")
>>> print(mon_obj)
Classe d'attribut_1 égal à toto
'''
return f"Classe d'attribut_1 égal à {self.attribut_1}"6 Template fonction
Voici un modèle que vous pouvez utiliser pour documenter vos fonctions
def ma_fonction(param1, param2):
"""description_courte
description_longue
Parameters
----------
param1 : type (str, int, float, list...)
description_param1
param2 : type
description_param2
Returns
-------
type_retour
description_retour
Examples
--------
>>> 1+1
2
>>> print("abc")
abc
>>> ma_fonction(xxx, yyy)
valeur_esperee
"""
return None
if __name__ == '__main__':
a = ma_fonction(p1, p2)
print(a)7 Template pytest
import pytest
from mon_fichier import ma_fonction
@pytest.mark.parametrize(
'param1, param2, resultat_attendu',
[
(1, 1, 2),
(1, 2, 3),
(2, 2, 4)
]
)
def test_ma_fonction(param1, param2, resultat_attendu):
assert ma_fonction(param1, param2) == resultat_attendu