Cours Python

Télécharger au format pdf ou txt
Télécharger au format pdf ou txt
Vous êtes sur la page 1sur 11

Université de Monastir

Faculté des Sciences de Monastir


Département des Sciences de l’Informatique
Programmation orientée objet avec Python
Matière : Informatique Classe : LSI2
Prof : Soumaya Gaâliche

I. Introduction :
Dans la partie précédente, on décrit les objets comme des variables pouvant contenir elle-même des
fonctions et variables.
Nous sommes allés plus loin tout au long de la seconde partie pour découvrir que nos fonctions
contenues dans nos objets sont appelées des méthodes. En vérité on a une définition pratique des
objets, alors que la dernière est POO (programmation orientée objet).
En Python, la liberté est plus grande que d’autres langage de programmation orientée objet. Après
tout, vous avez pu passer une partie de ce tutoriel sans connaître la façade objet de Python. Et pourtant,
le langage Python est totalement orienté objet : en Python, tout est objet, vous n'avez pas oublié ?
Quand vous croyez utiliser une simple variable, un module, une fonction…, ce sont des objets qui se
cachent derrière.
II. Les classes :
Les classes sont des fabriques d’objets : on construit d’abord l’usine avant de produire des objets ! On
instancie un objet (c-à-d qu’on le produit à partir de l’usine) en appelant le nom de sa classe comme
s’il s’agissait d’une fonction. Plus concrètement, une classe est un assemblage de variables appelles
attributs et des fonctions appelées méthodes.
Syntaxe :

class NomClasse :
#instruction1
#instruction2
La définition d’une classe est constituée du mot clé class, du nom de classe et de deux points,
une docstring commentant la classe (la chaîne de documentation est facultative elle contient le
message affiché par help(NomClass). Pour le nom de classe on doit mettre en majuscule (convention)
chaque lettre débutant un mot, par exemple : MaClasse.
On va modéliser une classe Point comme un exemple. Nous avons défini les attributs qui allaient
caractériser notre objet de classe Point.

>>> class Point:


""" classe définit un point caractérisée par une abscisse x et ordonnée y"""
x=2
y=4
defaffiche(self):
print("P({}, {})".format(self.x,self.y))

>>> help(Point)
Help on class Point in module __main__:

class Point(builtins.object)
| classe définit un point caractérisée par une abscisse x et ordonnée y
|
| Methodsdefinedhere:
|

Page 1 sur 11
| affiche(self)
|
| ----------------------------------------------------------------------
| Data descriptorsdefinedhere:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weakreferences to the object (if defined)
|
| ----------------------------------------------------------------------
| Data and otherattributesdefinedhere:
|
| x=2
|
| y=4
>>> p=Point() #p est une instance
>>> #affichage de coordonnées
>>>print(p.x)
2
>>>print(p.y)
4
>>> #appel à une méthode
>>>p.affiche()
P(2, 4)
III. Méthodes :
Une méthode s’écrit comme une fonction dans le corps de la classe avec un premier paramètre self
obligatoire (le nom self est une convention), où self représente l’objet (instance) sur lequel la méthode
sera appliquée, ainsi que les valeurs des attributs de ce dernier.
1. Méthodes spéciales :
Les méthodes spéciales sont des méthodes d’instance que Python reconnaît et sait utiliser dans certains
contextes. Elles peuvent servir à indiquer à Python ce qu’il doit faire quand il se retrouve devant une
expression comme mon_ojet1+mon_objet2, mon_objet[indice]. Et encore plus fort, elles contrôlent la
façon dont un objet se créé, ainsi que l’accès à ses attributs, ces méthodes portent des noms prédéfinis,
précédés et suivies de deux caractères de soulignement « __ ».

 Constructeur : __init__
Lors de l’instanciation d’un objet, la structure de base de l’objet est créée en mémoire, et la méthode
__init__ est automatiquement appelée pour initialiser l’objet. C’est typiquement dans cette méthode
spéciale que sont créés les attributs d’instance avec leur valeur initiale.

>>> class Point:


#constructeur
def __init__(self,x,y):
self.x=x
self.y=y

Une fois définie, une classe peut être utilisée pour créer des variables de type class Point, on parle
d’objets de type Point. La syntaxe est la suivante :

Page 2 sur 11
NomObj=NomClasse(param1,param2,…)

NB : On ne passe jamais le paramètre self lors de la création d’un objet. La création d’un objet à partir
d’une classe s’appelle instanciation de la classe et les objets sont appelés des instances.
>>> p=Point(2,3) #p est une instance de classe Point
>>> p
<__main__.Pointobjectat 0x0368CDB0>
>>> type(p)
<class '__main__.Point'>

Application :
Définir une classe étudient permettant de représenter un étudient. Les instances de cette classe sont
initialisées avec 4 attributs :
 Nins : le numéro d’inscription de l’étudient
 Nom : nom de l’étudient
 Filière : filière de l’étudient
 Note : liste contient les notes de l’étudient
Le constructeur de la classe prend 4 arguments en entrée, à partir desquels les attributs sont initialisés.
- Donner les lignes de code permettant de définir cette classe.
- Ajouter une méthode d’instance affiche permettant d’afficher les informations d’un objet de la
classe étudient.
- Ajouter une méthode calcul permettant de calculer puis de renvoyer la moyenne de l’étudient
(en supposant que toutes les matières de même coefficient).
 Destructeur : __del__
Lors de la suppression d’un objet, la méthode __del__ est automatiquement appelée pour le détruire de
la mémoire. Souvent on peut personnaliser le comportement de cette méthode spéciale.
 Méthode __repr__:

La méthode __repr__ ne prend aucun paramètre (sauf, bien entendu, self) et renvoie une chaîne de
caractères : la chaîne à afficher quand on entre l'objet directement dans l'interpréteur.On peut
également obtenir cette chaîne grâce à la fonction repr, qui se contente d'appeler la méthode
spéciale __repr__ de l'objet passé en paramètre.

 Méthode __str__ :

La méthode __str__ est spécialement utilisée pour afficher l'objet avec print. Par défaut, si aucune
méthode __str__ n'est définie, Python appelle la méthode __repr__ de l'objet. La méthode __str__ est
également appelée si vous désirez convertir votre objet en chaîne avec le constructeur str.

 Surcharge des opérateurs :


La surcharge permet à un opérateur de posséder un sens différent suivant le type de ses opérandes. Par
exemple, l’opérateur « + » permet :
- 12+3 #addition entière
- "bon" +"jour" #concaténation

Page 3 sur 11
Exemple :
Dans l’exemple suivant nous surchargeons l’opérateur d’addition pour le type Vecteur2D. Nous
surchargeons également la méthode spéciale __repr__ et __str__

>>> class Vecteur2D:


def __init__(self,x0,y0):
self.x=x0
self.y=y0
def __add__(self,second): #addition vectorielle
return Vecteur2D(self.x+second.x,self.y+second.y)
def __repr__(self):
#répresentation d'un vecteur 2D
return "Vecteur2D({},{})".format(self.x,self.y)
def __str__(self):
return "les coordonnées du vecteur sont x={},y={}".format(self.x,self.y)

>>> v1=Vecteur2D(1.2,2.356)
>>> v2=Vecteur2D(3.4,4.5)
>>> v3=v1+v2
>>>print(v3)
les coordonnées du vecteur sont x=4.6,y=6.856
>>> v3
Vecteur2D(4.6,6.856)
 Autres exemple des méthodes spéciales :
opérateur Méthode spéciale
== __eq__

!= __ne__

> __gt__

>= __ge__

< __lt__

<= __le__

+ __add__

- __sub__

* __mul__

** __pow__

/ __truediv

// __floordiv__

% __mod__

Page 4 sur 11
2. Méthodes non spéciales :

Une classe n’est pas constituée uniquement d’un constructeur, elle programme un ensemble
d’opérations applicables sur le type structuré en question ce qui la rend une bonne solution à certains
problèmes informatique en terme de robustesse du code, sécurité, réutilisabilité …
Les fonctions qu’on définit à l’intérieur d’une classe sont appelées des méthodes. Dans notre exemple,
on va essayer d’afficher, de déplacer et d’annuler un point :
>>> class Point:
def __init__(self,x,y):
self.x=x
self.y=y
defaffiche(self):
print("({},{})".format(self.x,self.y))
defdeplacer(self,dx,dy):
self.x+=dx
self.y+=dy
defannuler(self):
self.x=self.y=0

>>> p=Point(4,3)
>>>p.affiche()
(4,3)
>>>p.deplacer(3,7)
>>>p.affiche()
(7,10)
>>>p.annuler()
>>>p.affiche()
(0,0)

IV. Les objets comme paramètres des méthodes :


Supposons qu’on veut ajouter une méthode nommé « identique » qui compare les attributs d’un point
avec un autre :
>>>class Point:
def __init__(self,x,y):
self.x=x
self.y=y
defidentique(self,p):
return self.x==p.x and self.y==p.y

>>> p1=Point(6,4)
>>> p2=Point(6,41)
>>>p1.identique(p2)
False
>>> p3=Point(6,41)
>>>p3.identique(p2)
True

Page 5 sur 11
V. Création de classes à partir d’autres classes
Un segment est défini à partir de deux points A et B, on peut définir une classe segment avec deux
attributs de type class point et une méthode distance qui calcule la distance entre A et B:
>>> class Segment:
def __init__(self,a,b):
self.a=a
self.b=b
defdistance(self):
from math import sqrt
return sqrt((self.a.x-self.b.x)**2+(self.a.y-self.b.y)**2)

>>> s=Segment(Point(3,4),Point(4,6))
>>>s.distance()
2.23606797749979
>>>s.a.x
3
>>>s.a.y
4

VI. Encapsulation :
Comme on l’a bien remarqué, les attributs d’un objet sont accessibles en lecture et en écriture à
l’extérieur de la classe. Ceci est due au fait que les attributs, par défaut, sont publiques en Python. On
peut cependant cacher à l’utilisateur d’une classe la structure d’un objet et l’interdire de modifier
certains attributs si on le veut. Il suffit d’utiliser des attributs privés lors de la définition du
constructeur de la classe. Un attribut privé n’est accessible qu’à l’intérieur de la classe et il est spécifié
par deux tirets bas : __nomattribut. En cachant la structure d’un objet, on dit qu’on l’a encapsulé.
1. Solution1 :
>>> class Point:
def __init__(self,x,y):
self.__x=x
self.__y=y
defaffiche(self):
print(self.__x,self.__y)

>>> p=Point(3,5)
>>>p.x
Traceback (mostrecent call last):
File "<pyshell#24>", line 1, in <module>
p.x
AttributeError: 'Point' object has no attribute 'x'
>>>p.__x
Traceback (mostrecent call last):
File "<pyshell#25>", line 1, in <module>
p.__x
AttributeError: 'Point' object has no attribute '__x'
>>>p.affiche()
35

Page 6 sur 11
Pour permettre l’accès aux attributs à l’extérerieur de la classe, on définit des méthodes spéciales
appelées accesseurs :
- L’accesseur getattribut : retourne la valeur de l’attribut en question
- L’accesseur setattribut : modifie la valeur de l’attribut

>>> class Point:


def __init__(self,x,y):
self.__x=x
self.__y=y
defgetx(self):
return self.__x
defsetx(self,x):
self.__x=x
defgety(self):
return self.__y
defsety(self,y):
self.__y=y

>>> p=Point(3,5)
>>>p.getx()
3
>>>p.sety(4)
>>>p.gety()
4
2. Solution2 : en utilisant la classe «property »

Les propriétés permettant de faire croire à l’utilisateur d’une instance de classe qu’il utilise un attribut
alors qu’il utilise en réalité une ou plusieurs méthodes. A chaque fois que le programmeur veut
accéder à ce faux attribut (ou modifier sa valeur), il appelle une méthode qui permet d’accéder à cet
attribut (ou de modifier sa valeur).

Une propriété ne se créé pas dans le constructeur mais dans le corps de la classe. J’ai dit qu’il
s’agissait d’une classe, son nom est « property ». elle attend quatre paramètres, tous optionnels :

- La méthode donnant accès à l’attribut (fget)


- La méthode modifiant l’attribut (fset)
- La méthode appelée quand on souhaite supprimer l’attribut (fdel)
- La méthode appelée quand on demande de l’aide sur l’attribut (doc)

En pratique, on utilise surtout les deux premiers paramètres : ceux définissent les méthodes d’accès et
de modification, autrement dit nos accesseur et mutateur d’objet.

Syntaxe :

class NomClasse :

#code de la classe

nom_propriete=property(fget,fset,fdel,doc)

Page 7 sur 11
Exemple :

>>> class Personne:

"""Classe définissant une personne caractérisée par :

- son nom

- son prénom

- son âge

- son lieu de naissance"""

def __init__(self,nom,prenom):

"""constructeur de notre casse"""

self.nom=nom

self.prenom=prenom

self.age=33

self.__lieuResidence="Monastir" #notez les deux soulignés devant l'atribut

def __getlieuResidence(self):

"""methode qui sera appelée quand on souhaitera accéder en lecture à l'attribut


lieuResidence"""

print("on accéder à l'attribut lieuResidence")

return self.__lieuResidence

def __setlieuResidence(self,NR):

"""Methode appelée quand on souhaite modifier le lieu de residence"""

print("Attention, il semble que {} déménage à {}".format(self.prenom,NR))

self.__lieuResidence=NR

#on va dire à Python que notre attribut lieuResidence pointe vers une propriéte

lieu=property(__getlieuResidence,__setlieuResidence)

>>> p1=Personne("Mohamed","Ali")

>>> p1.nom

'Mohamed'

Page 8 sur 11
>>> p1.lieu #Python tombe sur une propriété redirigeant vers la méthode "__getlieuResidence"

on accéder à l'attribut lieuResidence

'Monastir'

>>> p1.lieu="Tunis" #Python appelle la méthode "__setlieuResidence"

Attention, il semble que Ali déménage à Tunis

>>> p1.lieu

on accéder à l'attribut lieuResidence

'Tunis'

VII. Attributs :

Il existe deux types d’attributs : attributs d’instance et attributs de classe, dans les exemples que nous
avons vus jusqu'à présent, nos attributs sont contenus dans notre objet. Ils sont propres à l'objet : si
vous créez plusieurs objets, les attributs Nins, nom,… de chacun ne seront pas forcément identiques
d'un objet à l'autre. Mais on peut aussi définir des attributs dans notre classe.

class Compteur:

"""Cette classe possède un attribut de classe qui s'incrémente à chaque

fois que l'on crée un objet de ce type"""

objets_crees = 0 # Le compteur vaut 0 au départ

def __init__(self):

"""À chaque fois qu'on crée un objet, on incrémente le compteur"""

Compteur.objets_crees += 1

On définit notre attribut de classe directement dans le corps de la classe, sous la définition et
la docstring, avant la définition du constructeur. Quand on veut l'appeler dans le constructeur, on
préfixe le nom de l'attribut de classe par le nom de la classe. Et on y accède de cette façon également,
en dehors de la classe. Voyez plutôt :

>>>Compteur.objets_crees
0
>>> a=Compteur() #on crée un premier objet
>>>Compteur.objets_crees
1
>>> b=Compteur() #on crée un autre objet
>>>Compteur.objets_crees
2

Page 9 sur 11
VIII. Le concept d’héritage et de polymorphisme :

1. Héritage :
Dans la vie, certains objets sont reliés par un lien hiérarchique. Un objet est un cas particulier d’un
autre ou l’inverse ou un objet est une généralisation d’un autre. On peut prendre l’exemple d’une
forme géométrique et d’un carré. Un carré est une forme géométrique spéciale et la forme géométrique
est une généralisation du carré, du rectangle…
Tous les langages orientées objets permettent d’illustrer cette notion de spécialisation/généralisation
via le concept d’héritage. Une classe fille hérite toujours d’une classe mère. Dans l’exemple cité, la
classe fille est bien entendu le carré et la classe mère est la forme géométrique.
Ceci permet une flexibilité dans le codage de logiciels de tailles et de complexités importantes mais on
ne va pas entrer dans ce détail. Par contre, on va essayer d’implémenter en python le concept
d’héritage en se basant sur les deux classes suivantes :

 La classe mère (super classe) : Personne : chaque personne possède un nom et un prénom
qu’on peut afficher sur écran
 La classe fille (sous classe) : Etudiant : chaque étudiant, à part son nom et son prénom, il a une
carte d’étudiant avec un numéro unique.

En python pour exprimer le lien de hiérarchie, on utilise la syntaxe suivante lors de la déclaration
d’une classe :
class fille(nom_classe_mère) :
La classe fille ale droit d’utiliser tous les attributs et les méthodes de la classe mère au sein de son
corps et elle peut rajouter d’autres attributs et méthodes propres à elle :
>>> class Personne:
def __init__(self,nom,prenom):
self.nom=nom
self.prenom=prenom
defaffiche(self):
print('{} {}'.format(self.nom,self.prenom),end='')

>>> class etudient(Personne):


def __init__(self,nom,prenom,numcart):
Personne.__init__(self,nom,prenom)
self.numcart=numcart
defaffiche(self): #rédéfinition de l'affichage
Personne.affiche(self)
print('{}'.format(self.numcart))

On remarque qu’on a aussi redéfinit la méthode affich() ; ceci est permis aussi.
Le constructeur d’étudiant appelle le constructeur de personne
>>> class Etudient(Personne):
def __init__(self,nom,prenom,numcart):
Personne.__init__(self,nom,prenom)
self.numcart=numcart

Page 10 sur 11
defaffiche(self): #rédéfinition de l'affichage
Personne.affiche(self)
print('{}'.format(self.numcart))

>>> e=Etudient('Mohamed','Ahmed',12345)
>>>e.affiche()
Mohamed Ahmed12345
On peut vérifier si une classe A hérite d’une classe B ou non avec la commande issubclass :
>>>issubclass(Etudient,Personne)
True

2. Le polymorphisme

En revenant à l’exemple précédent, on remarque que dans les deux classes mère et fille, on trouve
deux méthodes ayant des corps différents avec un même nom : Il s’agit des deux méthodes affich().
Supposons qu’on veut créer une liste L contenant un mélange d’objets de type personne et de type
etudiant à la fois:

>>> L=[Personne('aa','bb'),Etudient('xx','yy',32465),Personne('rr','aa')]

Et qu’on veut afficher ses éléments un par un sans se soucier de leurs natures (personne ou etudiant).
Ceci est possible grâce au concept de polymorphisme. En fait, la méthode affich() est une méthode
polymorphe c'est-à-dire qu’elle est capable de changer de comportement en fonction de l’objet qu’il
l’appelle d’où cette boucle pour afficher les objets de L :

>>> for i in L:
i.affiche()
print(end='\n')

aa bb
xx yy32465
rraa

En résumé, une méthode polymorphe est une méthode définie au sein d’une hiérarchie de classes
portant toujours le même nom et peut implémenter des traitements différents.

Page 11 sur 11

Vous aimerez peut-être aussi