Classes et POO
Classes
Python permet le paradigme Programmation Orienté Objet (POO).
Les objets groupent des données et des méthodes (fonctions) logiquement liées.
Par exemple, pour objets de type list
>>> nombres = [3, 1, 2]
>>> nombres.reverse()
>>> nombres.sort()
>>> nombres.pop()
Classes
Python permet le paradigme Programmation Orienté Objet (POO).
Les objets groupent des données et des méthodes (fonctions) logiquement liées.
Par exemple, pour objets de type list
>>> nombres = [3, 1, 2]
>>> nombres.reverse()
>>> nombres.sort()
>>> nombres.pop()
Données
Fonctions
Classes
Paradigme fonctionnel/procédural :
vec1 = (3, 4)
vec2 = (1, -3)
def longueur(v):
return math.sqrt(v[0]**2 + v[1]**2)
long1 = longueur(vec1)
long2 = longueur(vec2)
print(vec1[0]) # Affiche '3'
Classes
Paradigme fonctionnel/procédural :
vec1 = (3, 4)
vec2 = (1, -3)
def longueur(v):
return math.sqrt(v[0]**2 + v[1]**2)
long1 = longueur(vec1)
long2 = longueur(vec2)
print(vec1[0]) # Affiche '3'
Données
Fonctions
Classes
Paradigme OO : définir un nouveau type Vecteur pour grouper les données d'un vecteur et le fonction qui agissent dessus.
Vecteur
xy
longueur()
Classes
Paradigme OO : définir un nouveau type Vecteur pour grouper les données d'un vecteur et le fonction qui agissent dessus.
vec1 = Vecteur(3, 4) # création d'un objet Vecteur
vec2 = Vecteur(1, -3) # création d'un objet Vecteur
long1 = vec1.longueur()
long2 = vec2.longueur()
print(vec1.x) # affiche 3
Classes
Paradigme fonctionnel/procédural
chat1 = ('Felix', 5)
chat2 = ('Cléo', 7)
def affiche_age(c):
print('{} a {} ans'.format(c[0], c[1]))
affiche_age(chat1)
affiche_age(chat2)
Classes
Paradigme OO :
chat1 = Chat('Felix', 5)
chat2 = Chat('Cléo', 7)
chat1.affiche_age()
print(chat.nom)
Chat
nomage
affiche_age()
Classes
Ces nouveaux types s'appellent classes.
Une nouvelle classe est définie par le mot-clé class.
class NomDeLaClasse:
<instruction 1>
<instruction 2>
.
.
.
<instruction N>
Classes
La définition d'une classe :
class Vecteur:
'''Cette classe représente un vecteur.'''
def __init__(self, a, b):
self.x = a
self.y = b
def longueur(self):
return math.sqrt(self.x**2 + self.y**2)
Création d'instances de la classe = objets :
vec1 = Vecteur(3, 4) # appel de __init__(..., 3, 4)
# aucun argument pour 'self'
print(vec1.x) # Affiche '3'
Classes
class Vecteur:
'''Cette classe représente un vecteur.'''
def __init__(self, a, b):
self.x = a
self.y = b
def longueur(self):
return math.sqrt(self.x**2 + self.y**2)
Finalement, on peut appeler les méthodes sur l'objet :
long = Vecteur.longueur(vec1)
Syntaxe alternative, plus pratique (sans argument explicite pour self):
long = vec1.longueur()
Classes
class Chat:
'''Cette classe représente un chat.'''
def __init__(self, n, a):
self.nom = n
self.age = a
def affiche_age(self):
print('{} a {} ans'.format(self.nom, self.age))
def parle(self):
print('miaou')
monchat = Chat('Felix', 5)
monchat.affiche_age()
monchat.parle()
Classes
Deux syntaxe pour appeler les méthodes :● objet.methode() syntaxe courante (implicitement transformée dans
la deuxième)● Classe.methode(objet)
class Chat :
def parle(self):
print('miaou')
monchat = Chat()
monchat.parle() # Ces deux appels
Chat.parle(monchat) # sont équivalents
Classes
Quelques conventions.
● nom des classes : en « CamelCase »
Vecteur
PlanCartesien
Chat
MainWindow
● nom des objet : en minuscule (avec tirets bas)
vec = Vecteur(1, 2)
vec_longue = Vecteur(35,-43)
plan_cartesien = PlanCartesien()
chat1 = Chat('Felix', 5)
main_win = MainWindow()
Classes
Les méthodes ont toujours un premier argument qui représente, dans la méthode, l'objet = l'instance particulière.
Par convention, on l'appelle self.
...
def presente(self):
print('{} a {} ans'.format(self.nom, self.age))
def parle(self, n):
print('miaou ' * n)
def parle_beaucoup(self):
self.parle(10)
...
Classes
On peut définir des attributs pour les classes aussi (class attributes = attributs de classe), par affectation.
Ils sont en commun pour toutes les objet crée par la classe.
Souvent utilisés pour les « constantes » du type.
class Cercle:
PI = 3.14159
def __init__(self, r):
self.rayon = r
def aire(self):
return Cercle.PI * self.rayon ** 2
print('La valeur de PI est {}'.format(Cercle.PI))
c = Cercle(2.5)
print('rayon = {}, aire = {}'.format(c.rayon, c.aire()))
Classes
Un objet peut être composé par des autres objets.
Exemple : un rectangle est défini par deux points.
a = Vecteur(1, 2)
b = Vecteur(5, 4)
class Rectangle:
def __init__(self, p1, p2):
self.p1 = p1
self.p2 = p2
def aire(self):
largeur = self.p2.x – self.p1.x
hauteur = self.p2.y – self.p1.y
return largeur * hauteur
rect = Rectangle(a, b)
print(rect.aire())
Vecteur
x = 1y = 2
Vecteur
x = 5y = 4
Rectangle
aire()
p2 =
p1 =
Classes
Il n'y a pas d'attributs privés en Python, tout est toujours accessible.
Une convention est de préfixer avec un seule tiret bas les attributs qu'on veut protéger. Mais c'est juste une « suggestion » aux programmateurs.
class Chat:
def __init__(self):
self._age = 0
def set_age(self, age):
self._age = max(age, 0)
def get_age(self):
return self._age
Ce code suggère au programmateur qui veut utiliser la classe Chat, de ne pas toucher à _age et utiliser seulement set_age() et get_age().
Méthodes spéciales
On a rencontré pour la première fois une méthode spéciale __init__ (le constructeur).
Les méthodes spéciales sont identifiées par deux tirets bas à chaque côtés du nom.
class Chat:
def __init__(self, n, a):
self.nom = n
self.age = a
def parle(self, x):
print('miaou ' * x)
La fonctions repr()
La fonction repr() donne une représentation textuelle de n’importe quel objet, sous forme de chaîne.
>>> repr(4)
'4'
>>> def fun(x):
... return x + 2
>>> repr(fun)
'<function fun at 0x7f73ecad1ea0>'
>>> fichier = open('topics.txt')
>>> repr(fichier)
"<_io.TextIOWrapper name='topics.txt' mode='r' encoding='UTF-8'>"
Elle est utilisée dans l’interpréteur pour afficher les objets.
Méthodes spéciales
Pour les instances de classes, la conversion standard donne une chaîne du genre '<nomdumodule.nomdelaclasse object at 0xffff>'.
>>> class Vecteur:
... def __init__(self, x, y):
... self.x = x
... self.y = y
...
>>> p = Vecteur(3, 5)
>>> repr(p)
'<__main__.Vecteur object at 0x7f6d305b9ab8>'
Méthodes spéciales
Pour contrôler cette conversion il faut définir une méthode spéciale __repr__.
>>> class Vecteur:
... def __init__(x, y):
... self.x = x
... self.y = y
... def __repr__(self):
... return 'Vecteur({}, {})'.format(self.x, self.y)
...
>>> v = Vecteur(3, 5)
>>> repr(v)
'Vecteur(3, 5)'
>>> v
Vecteur(3, 5)
Méthodes spéciales
Sous le capot : la fonction repr appelle la méthode spéciale __str__ de l’objet.
repr(x) x.__repr__()
Tout se passe comme repr() était définie avec :
def repr(x):
return x.__repr__()
Méthodes spéciales et opérateurs
Méthodes spéciales
On peut utiliser les opérateurs + - * / < > etc... avec des objets. Par exemple, pour l'operateur + il faut définir une méthode __add__()
class Vecteur:
...
def __add__(self, other):
x = self.x + other.x
y = self.y + other.y
return Vecteur(x, y)
...
>>> v1 = Vecteur(3, 5)
>>> v2 = Vecteur(2, -1)
>>> v1 + v2 # équivalent à v1.__add__(v2)
# v1 est ‘self’ et v2 est ‘other’
Vecteur(5, 4)
Méthodes spéciales
+ __add__
- __sub__
* __mul__
/ __truediv__
// __floordiv__
< __lt__ (less than)> __gt__ (greater than)<= __le__ (less or equal)>= __ge__ (greater or equal)== __eq__
...