Définir une classe Date avec trois attributs:
Lorsqu'un attribut concerne tous les objets d'une même classe, on parle d'attribut de classe
Ainsi pour la lisibilité des objets on va introduire un attribut de classe à la classe Date, sous la forme d'une liste nom_mois, permettant l'affichage d'une date sous la forme "15 septembre 2021" plutôt que 15/09/21
class Date:
nom_mois = ['#', 'janvier','février',...]
#à compléter
def __init__(self,j,m,a):
pass
Cet attribut de classe peut être utilisé sous la forme Date.nom_mois
Avec les méthodes suivantes :
On peut vouloir comparer des dates. Python propose une méthode particulière à définir pour cela __lt__(self,other) qui renvoie Vrai si l'objet en cours de construction self est strictement plus petit que la date other
Compléter le code suivant et tester le
def __lt__(self,other):
return self.annee < other.annee or\
(self.annee == other.annee and self.mois < other.mois) or\
#... à compléter
Il existe aussi des méthodes qui ne s'appliquent pas à un objet en particulier mais servent de fonction d'aide pour tous les objets définis par la classe
On peut soit définir cette fonction à l'extérieur de la classe et l'appeler à l'intérieur de la classe où l'insérer dans la classe sans self dans les paramètres
Compléter le code suivant
def max(date1,date2):
if date1.annee > date2.annee :
return date1
elif date2.annee > date1.annee :
return date2
elif date1.mois > date1.mois :
# à compléter
Si on appelle cette méthode de classe à l'extérieur de la classe on procède ainsi par exemple
date1 = Date(12,09,2021)
date2 = Date(12,03,2022)
print(Date.max(date1,date2))
A quel moment contrôle-t-on la validité des données?
La classe Date telle que l'on a écrit précedemment suppose que l'on a "filtré" les dates avant de les insérer dans le constructeur
Si on a oublié de le faire on peut se retrouver avec des dates comme 32/15/2021 !
Pire les valeurs ne sont peut être pas entières!
Nous sommes habitués aux messages d'erreur dans la console
S'il y a plusieurs erreurs dans un programme, une erreur de syntaxe ou une erreur de calcul, le programme s'arrête à la première erreur rencontrée
Dans le langage Python un certain nombre d'erreurs est déjà répertorié comme par exemple une division par zéro
Dans notre cas nous devons définir ce qui est invalide et sera considéré comme une erreur qui arrêtera le programme dès son interception
Dans un premier temps on va définir une méthode de classe jour_est_valide(j) où on teste si le jour est de type entier et est compris entre 1 et 31, si ce n'est pas le cas on lève une erreur qui est un objet de type ValueError avec un message approprié "le jour "+ str(j) + " est invalide" passé en paramètre du constructeur de l'objet ValueError
class Date2:
#attribut de classe
nom_mois = ["#",'janvier','fevrier','mars','avril','mai',
'juin','juillet','août','septembre','octobre','novembre','décembre']
#méthodes de classe
def jour_est_valide(j):
return isinstance(j,int) and (1 <= j <= 31)
Ensuite dans le constructeur on écrit
def __init__(self,j,m,a):
if Date2.jour_est_valide(j):
self.jour = j
else:
raise ValueError("le jour "+ str(j) + " est invalide")
Compléter le code pour tester le mois et l'année puis ensuite réaliser les tests suivants
date1 = Date2((2,1),1,2022)
date2 = Date2("Lundi",1,2022)
date3 = Date2("Lundi",15,2022)
On observe que le programme s'arrête dès la première erreur car le jour est de type tuple au lieu de int, les deux dernières instructions ne sont pas exécutées
Pour que le programme soit exécuté dans son intégralité malgré les erreurs rencontrées on encadre les sources d'erreurs possibles par le bloc try ...except dans le constructeur
class Date3:
#attribut de classe
nom_mois = ["#",'janvier','fevrier','mars','avril','mai',
'juin','juillet','août','septembre','octobre','novembre','décembre']
#méthode de classe
def jour_est_valide(j):
return isinstance(j,int) and (1 <= j <= 31)
def __init__(self,j,m,a):
try:
if Date3.jour_est_valide(j):
self.jour = j
else:
raise ValueError
except:
print("le jour "+ str(j) + " est invalide")
Compléter le constructeur et réaliser les mêmes tests que précédemment et observer que cette fois ci le programme ne s'arrête pas et délivre tous les messages d'erreur d'un coup
Un système d'exploitation propose de trier les fichiers contenus dans un répertoire par différentes entrées possibles(en simplifiant):
Définir une classe Fichier, les attributs sont nom de type str, date de type Date (voir plus haut) et taille de type int
On commence par définir une méthode __lt__(self,other) qui retourne vrai si un fichier est strictement plus petit qu'un autre suivant la date d'ajout
On rappelle qu'en Première on a implémenté le tri par insertion pour des entiers ou des chaînes de caractères
def insertion(T,i):
"""
La liste T contient des entiers
ou des chaines de caractères
est triée de l'indice 0
jusqu'à l'indice i - 1
i >= 1
On insère T[i] à sa place et à la fin
La liste T est triée de l'indice 0
jusqu'à l'indice i
"""
temp = T[i]
j = i
while j > 0 and T[j-1] > temp:
T[j] = T[j-1]
j -= 1
T[j] = temp
def tri_insertion(T):
"""
tri par insertion la liste T
contenant des nombres ou des chaines de caractères
"""
for i in range(1,len(T)):
insertion(T,i)
nous allons l'adapter pour des fichiers avec le comparateur défini ci-dessus
def insertion(T,i):
"""
La liste T contient des fichiers
comparables suivant leur date d'ajout
est triée de l'indice 0
jusqu'à l'indice i - 1
i >= 1
On insère T[i] à sa place et à la fin
La liste T est triée de l'indice 0
jusqu'à l'indice i
"""
temp = T[i]
j = i
#on peut utiliser > à cause de __lt__()
while j > 0 and T[j-1] > temp:
T[j] = T[j-1]
j -= 1
T[j] = temp
def tri_insertion(T):
"""
tri par insertion la liste T
contenant des nombres ou des chaines de caractères
"""
for i in range(1,len(T)):
insertion(T,i)
On n'a résolu que partiellement le problème car on ne peut pas utiliser la fonction tri_insertion(T) pour trier les fichiers suivant leur taille ou leur nom
Pour plus de généralité on va donc créer un objet Comparateur ayant un attribut nom, valant soit 'taille', soit 'nom' et soit 'date'
Cet objet n'a qu'une seule méthode plus_petit(self,x,y) qui en fonction du nom du comparateur compare les fichiers x et y avec l'opérateur <
Ce qui suppose que pour un attribut d'un autre type que int,float ou str la méthode __lt__() ait été implémentée pour donner un sens à l'opérateur <
class Comparateur:
def __init__(self,nom):
self.nom = nom
def plus_petit(self,x,y):
if self.nom== 'taille':
return x.taille < y.taille
if self.nom == 'date':
return x.date < y.date
if self.nom == 'nom':
return x.nom < y.nom
Maintenant on peut trier les fichiers suivant n'importe quel attribut du fichier en ajoutant comme paramètre à insertion(T,i) et tri_insertion(T) un comparateur comp
def insertion(T,i,comp):
"""
La liste T est triée de l'indice 0
jusqu'à l'indice i - 1
i >= 1
On insère T[i] à sa place et à la fin
La liste T est triée de l'indice 0
jusqu'à l'indice i
"""
temp = T[i]
j = i
while j > 0 and comp.plus_petit(temp,T[j-1]):
T[j] = T[j-1]
j -= 1
T[j] = temp
def tri_insertion(T,comp):
"""
tri par insertion la liste T
contenant des nombres ou des chaines de caractères
"""
for i in range(1,len(T)):
insertion(T,i,comp)
A l'exécution on peut avoir par exemple
date1 = Date(15,1,2022)
date2 = Date(17,1,2022)
date3 = Date(15,2,2022)
fic1 = Fichier('programme1',date1,1000)
fic2 = Fichier('texte1',date2,300)
fic3 = Fichier('image',date3,100)
c1 = Comparateur('nom')
c2 = Comparateur('date')
c3 = Comparateur('taille')
liste_fichiers = [fic1,fic2,fic3]
#tri suivant le nom
tri_insertion(liste_fichiers,c1)
#tri suivant la date
tri_insertion(liste_fichiers,c2)
#tri suivant la taille
tri_insertion(liste_fichiers,c3)