42 0 416KB
Python
Programmation orientée objet
Suite sur les fichiers La première ligne de cet exemple importe l'intégralité du module os, lequel contient de nombreuses fonctions intéressantes pour l'accès au système d'exploitation. La seconde ligne utilise la fonction getcwd() du module os Comme vous pouvez le constater, la fonction getcwd() renvoie le nom du répertoire courant (getcwd = get current working directory). >>> import os >>> rep_cour = os.getcwd() >>> print rep_cour '/home/housni'
Suite sur les fichiers Si vous souhaiterez forcer Python à changer son répertoire courant, afin que celui-ci corresponde à vos attentes. Pour ce faire, utilisez les commandes suivantes en début de session. (Nous supposons ici que le répertoire visé est le répertoire /home/exercices . Vous pouvez utiliser cette syntaxe (c'est-àdire des caractères / et non \ en guise de séparateurs : c'est la convention en vigueur dans le monde Unix). Python effectuera automatiquement les conversions nécessaires, suivant que vous travaillez sous MacOS, Linux, ou Windows. >>> from os import chdir >>> chdir("/home/exercices")
Introduction à la programmation orientée objet Dans ce chapitre, nous allons créer nos premières classes, nos premiers attributs et nos premières méthodes. Nous allons aussi essayer de comprendre les mécanismes de la programmation orientée objet en Python. Python offre la possibilité de programmer en Orienté objet. Le mécanisme de classe en Python est un mélange des mécanismes de classes de C++ et de Modula-3.
La synthaxe… La forme la plus simple de définition de classe ressemble à ceci : class Nomclasse:
…
Dans la pratique, les instructions à l’intérieur de la définition de classe seront souvent des définitions de fonctions, mais d’autres instructions sont acceptées. L’objet classe permet deux types d’opération : La référenciation des attributs et l’instanciation. La référence d’attributs : Nomclasse.i où i est un attribut de Nomclasse est une références d’attribut valide. L’instanciation(création d’une instance (objet) Nomclasse): x=Nomclasse() affecte la nouvelle instance à la variable x
A l’intérieur de la classe… On trouve deux types d’attributs : -
données (idem que les données membre en C)
-
Les méthodes (idem que fonction membre en C)
1)
Les données Les données n’ont pas besoin d’être déclarée; Comme les variable locale, elles apparaissent lorsqu’on leur affecte une valeur la première fois. ex : class MaClasse : def f(x): print « hello World » i=123456 x= MaClasse() x.compteur = 1 #creation de l’attribut compteur
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). Les atti sont des attributs d'instance, ils sont propres à l'objet, créés et détruits avec lui.
Exemple class exemple: var1=12 def __init__(self,v): self.var1=v def afficheAttClasse(self): print(exemple.var1) def afficheAttInstance(self): print(self.var1) def plus1(self): exemple.var1+=1 x=exemple(33) y=exemple(44) x.afficheAttInstance() x.afficheAttClasse() y.plus1() x.afficheAttInstance() x.afficheAttClasse()
A l’intérieur de la classe… 2) Les méthodes Une méthode est appelée comme en C++ : x.f() Vous avez surement remarqué que la fonction f définie dans MaClasse a été appelée sans paramètre alors que la définition en contenait un. Ca devrait normalement déclencher une exception. Mais il n’en est rien car la particularité des méthodes est que l’objet est passé comme premier argument de la fonction. Le plus souvent par convention appelé « self » pour amélioré la lisibilité du programme . L’appel x.f() est donc équivalent à MaClasse.f(x). Il n’est pas nécessaire que la définition de la méthode soit comprise dans la définition de la classe. Ex : def f1 (self,x,y): return min(x,x+y) class C: f=f1
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é !
Méthodes prédéfinies… Python contient une liste de méthodes dites spéciales :
En particulier, la méthode __init__(self)… Lorsqu’une classe définit la méthode spéciale __init__(), l’instantation de la classe appelle automatiquement cette méthode. Il s’agit en fait de ce qu’on appel en C++ un constructeur. Bien sûr, la méthode __init__() peut prendre autant de paramètre qu’on le vaut, pour une flexibilité accrue… Ex : class Complexe: def __init__(self, partiereelle, partieimaginaire): self.r = partiereelle self.i = partieimaginaire x = Complexe(3.0,-4.5) x.r, x.i donne: (3.0, -4.5)
L’héritage
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éristiques (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
L’héritage
Lorsqu'une classe hérite d'une autre elle peut :
Utiliser les attributs de la classe parent
Utiliser les méthodes de la classe parent
définir de nouveaux attributs
définir de nouvelle méthodes
Redéfinir certaines méthodes
L’héritage
Lorsqu'une classe hérite d'une autre elle peut :
Utiliser les attributs de la classe parent
Utiliser les méthodes de la classe parent
définir de nouveaux attributs
définir de nouvelle méthodes
Redéfinir certaines méthodes
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
Exemple class Voiture: roues = 4 moteur = 1 def __init__(self): self.nom = "A déterminer" def allumer(self): print "La voiture démarre" class VoitureSport(Voiture): def __init__(self): self.nom = "Ferrari"
>>> ma_voiture=Voiture() >>> ma_voiture.nom 'A déterminer' >>> ma_voiture.roues 4 >>> ma_voiture_sport=VoitureSport() >>> ma_voiture_sport.nom 'Ferrari' >>> ma_voiture_sport.roues 4 >>> ma_voiture_sport.allumer() La voiture démarre
Polymorphisme / surcharge de méthode class Voiture: roues = 4 moteur = 1 def __init__(self): self.nom = "A déterminer" def allumer(self): print "La voiture démarre" class VoitureSport(Voiture): def __init__(self): self.nom = "Ferrari" def allumer(self): print "La voiture de sport démarre"
>>> ma_voiture=Voiture() >>> ma_voiture.nom 'A déterminer' >>> ma_voiture.roues 4 >>> ma_voiture_sport=VoitureSport() >>> ma_voiture_sport.nom 'Ferrari' >>> ma_voiture_sport.roues 4 >>> ma_voiture_sport.allumer() La voiture de sport démarre
Polymorphisme / surcharge de méthode il est possible d'appeler la méthode du parent puis de faire la spécificité de la méthode. On peut d'ailleurs appeler n'importe quelle autre méthode. class Voiture: roues = 4 moteur = 1 def __init__(self): self.nom = "A déterminer" def allumer(self): print "La voiture démarre" class VoitureSport(Voiture): def __init__(self): self.nom = "Ferrari" def allumer(self): Voiture.allumer(self) print "La voiture de sport démarre" ma_voiture_sport = VoitureSport() ma_voiture_sport.allumer()
La voiture démarre La voiture de sport démarre
L’héritage La syntaxe pour définir une classe dérive est la suivante : Class Nomclassedérivée (NomClassedeBase):
…
Remarque : A la place d’un nom de classe de base, une expression est acceptée. Ce qui est utile lorsque le définition de la classe de base se trouve dans un autre module.. Ex : class NomClasseDerivee(nommod.NomClasseDeBase): L’exécution d’une définition de classe dérivée se déroule comme une classe de base. Quand l’objet classe est construit, la classe de base est mémorisée.C’est ce qui permet de trouver facilement un attribut. Lorsqu’un attributs est référence, il est recherché dans la classe dérivée s’il ne s’y trouve pas on le recherchera dans la classe de base.
L’héritage multiple Python supporte également l’héritage multiple. Une définition de classe avec plusieurs classes de base ressemble à : Class NomClasseDerivee (Base1,Base2,..,BaseN)
…
Lorsqu’on référence un attribut, la recherche s’effectue en profondeur càd de gauche à droite? Donc si un attribut n’est pas trouvé dans ClasseDerivee, on le cherchera d’abord dans base1, puis dans base2, et ainsi de suite jusqu’à ce qu’on le trouve… Rem : Il faut faire attention aux conflits accidentelles!! Par exemple, si on crée une classe dérivée de deux autres classes dérivées de la même classe de base…risque de problèmes!!!!