Chapitre 4 LES CLASSES ET LES OBJETS EN PYTHON La création d'une classe en python L'objet virtuel self et l'opérateur « . » Class NomClasse(object): Class Carte (object): def __init__(self,p1,p2,....,pP): self.att1=f(p1,p2,...pP) .... self.attN=f(p1,p2,...pP) def meth1(self,...): ... ... def methM(self,...): ... def __init__(self,h,c,l,L,cV="bleu"): self.nom=str(h)+c self.l=l self.L=L self.verso=cV def changeVerso(self,coul): self.verso=coul def draw(self): ... Attribut d'instance vs. de classe Class NomClasse(object): • "Description de la classe" attc1,...,attcC=val1,...,valC def __init__(self,p1,p2,....,pP): self.atti1=f(p1,p2,...pP) .... self.attiN=f(p1,p2,...pP) • def meth1(self,...): ... ... def methM(self,...): ... • Les attc sont des attributs de classe : toute instance de la classe peut y accéder. S'ils sont modifiés par un objet, ils sont modifiés pour les autres instances (soulignés en UML). Ex : L'attribut de classe standard __doc__ reçoit la valeur de la chaîne de description de la classe Les atti sont des attributs d'instance, ils sont propres à l'objet, créés et détruits avec lui. Classes prédéfinies en python ● ● ● ● ● Les classes de base que vous connaissez : int, float, str, list, tuple, dict Les classes à importer que vous connaissez : math, string, Tkinter Obtenir des informations sur une classe d'objet : dir(classe) – help(classe) - class.__doc__ Obtenir des informations sur les méthodes ou les attributs d'une classe : – help(classe.attribut) – help(classe.méthode) – methode.__doc__ On peut remplacer classe par n'importe qu'elle instance de classe La création d'instances en python 3p=Carte(3,"P",5,8,"violet") Création de variables et fonctions dc=Carte("D","C",5,8) Création de variables et fonctions 3p.nom="3P" dc.nom="DC" 3p.l=5 dc.l=5 3p.L=8 dc.L=8 3p.verso="violet" dc.verso="bleu" 3p.changeVerso(coul): dc.changeVerso(coul): 3p.verso=coul dc.verso=coul 3p.draw(): dc.draw(): Exemples de méthodes prédéfinies ● Pour une chaine s : split – ● Pour une liste l : append – ● l.append('c') : retourne None mais modifie l « sur place » en ajoutant le caractère 'c' en fin de liste Pour un dictionnaire d : – ● s.split() : retourne la liste des caractères de s d.keys() : retourne la liste des clés du dictionnaire Les fonctions standards sont en fait des méthodes maquillées : – – len(s) : compilé en s.__len__() a+b : compilé en a.__add__(b) Bonnes habitudes ● ● ● ● Les noms de classe commencent toujours par une majuscule (python recèle beaucoup de mauvais exemples...) Les noms d'attributs ou de méthodes ne commencent jamais par une majuscule ! Les noms doivent être le plus explicites possible Si ils sont composés de plusieurs mots ils sont tout attachés avec chaque mot qui commence par une majuscule (sauf le premier dans les cas des attributs et des méthodes) Les deux premiers grands principe : résumé ● Premier grand principe : l'instanciation – ● Opération permettant de construire des objets à partir d'une définition commune de leur structure : la classe Deuxième grand principe : l'encapsulation – – – – Un objet ramasse en lui même ses données (les attributs) et le code capable d'agir dessus (les méthodes) La liste des méthodes accessibles à l'utilisateur constitue l'interface de l'objet L'interface permet de cacher à l'utilisateur de l'objet les détails de l'implémentation Tous les langages OO n'imposent pas de respecter ce principe : le programmeur doit personnellement y veiller Chapitre 5 Troisième grand principe : l'héritage Notion de classe dérivée ou classe fille ou sous-classe ● ● ● Il est possible de définir une classe spécialisée à partir d'une autre classe plus générale (dite classe de base ou classe mère ou super-classe) La nouvelle classe (dite dérivée) permet à un objet qui l'instancie d'hériter des caractériques (attributs et méthodes) décrites par la classe héritée La classe dérivée peut ensuite subir des modifications : – – – Définition de nouveaux attributs et de nouvelles méthodes Redéfinition de méthodes de la classe de base Extension de méthodes de la classe de base Chaîne de classes dérivées ● ● ● ● Une nouvelle classe peut être définies à partir d'une classe elle même dérivée La suite des classes ainsi obtenue constitue une chaîne de classe : traduction du principe naturel de généralisation/spécialisation EtreVivant <-- Animal <-- Mamifere <-- Elephant <-ElephantDAsie <-- ElephantFemelleDAsie Résolution des références aux attributs et aux méthodes : recherche dans la classe correspondante, en descendant la chaîne des classes si besoin ; la référence est valide si la recherche aboutit Relation entre classe mère et fille ● ● ● L'héritage dénote une relation de généralisation / spécialisation Toute relation d'héritage peut se traduire par la phrase : « La classe dérivée est une version spécialisée de la classe de base » Le principe de généralisation/spécialisation invoque donc une relation dite relation est-un Avantages de l'héritage ● ● ● ● ● ● Factorisation de comportements communs à une hiérarchie : code de taille plus faible Lors d'une dérivation, seul le code spécifique reste à écrire : développement plus rapide Modélisation d'une notion très naturelle : systèmes conceptuellement bien conçus Permet le principe du polymorphisme fort Plus une classe est haute dans la hiérarchie plus son code est sollicité donc débogué rapidement Si la hiérarchie est bien pensée : permet une programmation différentielle Chapitre 6 COMPLÉMENT DE NOTATION UML Notation UML de la relation d'héritage ● La relation d'héritage est signalée par une flèche à l'extrémité triangulaire et dont la pointe est orientée vers la classe mère. EtreVivant Animal Mamifere Baleine Elephant ElephantDAsie ElephantDAfrique Notation complète des attributs Visibilité /nom:type[multiplicité{contrainte}]=val_attc {propriétés} ● Visibilité : « - » : attribut privé (private) – « # » : attribut protégé (protected) – « + » : attribut public / : Attribut dérivé (déduit d'autres attributs de la classe) – ● ● Type : type de donnée ● Multiplicité : condense l'expression de la structure ● val_attc : utile pour la valeur des attributs de classe ● Propriété : information complémentaire sur l'attribut (ex : frozen) Notation complète des méthodes visibilité nom (paramètre1,paramètre2...):type_ret {propriétés} ● Paramètres : direction nom:type =val_défaut avec direction : in : passé par valeur, pas disponible pour l'appelant (valeur par défaut) – out : valeur de sortie uniquement, disponible pour l'appelant – inout : passé par référence, disponible pour l'appelant Type_ret correspond au type de donnée que retourne la méthode (void si aucun retour attendu) – ● ● {propriété} correspond à des informations complémentaires Représentation graphique Carte -hauteur:string{frozen} -couleur:string{frozen} -/nom:char[2{ordered}]{frozen} -dimension:int[2] +ordres:dict={...} +corresp:dict={...} {nom=f(hauteur,couleur,corresp)} +comparerBridge(in c:Carte):string +dessiner():void dc:Carte 3p:Carte "dame":hauteur "coeur":couleur nom:"DC" [6,11]:dimension {...}:ordres {...}:corresp 3:hauteur "pique":couleur nom:"3P" [6,11]:dimension {...}:ordres {...}:corresp Chapitre 7 L'héritage en python La visibilité en Python ● Pas de propriétés privées ou protégées ● Mais simulation de private : variables « brouillées » – – – – Un attribut d'une instance o d'une classe C est brouillé si son nom est définit dans C avec la forme : __nom Il est renommé automatiquement à la création de l'instance o et n'est donc plus accessible « hors » de C sans connaître le mécanisme précis ! En fait il est renommé _C__nom et est accessible sous cette forme comme tous les attributs de o (car stocké ainsi dans le dictionnaire o.__dict__) Contourner l'impossibilité d'accès direct à une variable brouillée n'a pas de sens et est fortement déconseillé ! Héritage ● Nous avons vu sans le nommé le concept d'héritage dès la création de notre première classe : en python toute chaîne de classe devrait commencer par la classe object Class Carte(object): "description de la classe" ...