Telechargé par Ines Ghorbel

chapitre 2 l'heritage avec python

publicité
Héritage
Héritage
Création de nouvelles classes à partir de classes déjà définies :
class ClasseDerivee(ClasseDeBase):
<instruction 1>
<instruction 2>
.
.
.
<instruction N>
Si un attribut n'est pas trouvé dans la définition de la classe
dérivée, Python cherche récursivement dans la classe de base etc.
Héritage
Pour dériver la classe B de la class A :
class A:
def mA(self):
print('A')
class B(A):
def mB(self):
print('B')
A
mA
B
mB
b = B()
b.mB()
b.mA() # Les attributs de A sont accessibles
Héritage
Les classes dérivées peuvent remplacer les méthodes de la classe de
base.
class A:
def m(self):
print('A')
class B(A):
def m(self):
print('B')
b = B()
b.m()
# Affiche “B”
A
m
B
m
Héritage
Attention ! En Python les méthodes sont « virtuelles » par défaut.
class A:
def f(self):
self.m()
def m(self):
print('A')
class B(A):
def m(self):
print('B')
b = B()
b.f()
# Affiche “B”
A
f
m
B
m
Héritage
Si jamais une méthode de B veut exécuter la méthode originale de A (chain-up) il
faut utiliser la syntaxe alternative pour appeler les méthodes :
nomclasse.methode(objet)
class A:
def met(self):
print('A')
class B(A):
def met(self):
A.met(self)
print('B')
x = B()
x.met()
# Affiche “A” et “B”
Héritage
Alternative : la fonction super()
class A:
def met(self):
print('A')
class B(A):
def met(self):
super().met()
print('B')
x = B()
x.met()
# Affiche “A” et “B”
Héritage
On trouve souvent le chain-up dans les méthode d'initialisation :
class A:
def __init__(self, x):
self.x = x
class B(A):
def __init__(self, x):
super().__init__(x)
self.foo = 'bar'
b = B(5)
Ici b.x == 5 et b.foo == 'bar'.
Personne
prenom
nom
Héritage
class Personne:
def __init__(self, prenom, nom):
self.prenom = prenom
self.nom = nom
Professeur
cours
class Professeur(Personne):
def __init__(self, prenom, nom, cours):
super().__init__(prenom, nom)
self.cours = cours
class Etudiant(Personne):
def __init__(self, prenom, nom, numero):
super().__init__(prenom, nom)
self.numero = numero
p = Professeur('Pierre', 'Curie', 'Physique')
e = Etudiant('Maria', 'Skłodowska', '0123456789')
Etudiant
numero
Héritage multiple
class A:
foo = 'A'
class B:
bar = 'B'
A
B
foo
bar
C
class C(A, B):
pass
print(C.foo, C.bar)
# Affiche “A B”
Héritage multiple
class A:
foo = 'A'
class B(A):
pass
class C:
foo = 'C'
class D(B, C):
pass
print(D.foo)
A
foo
B
C
foo
D
Héritage multiple
Python utilise l'algorithme
« depth first » : on cherche
en profondeur dans une
branche avant de passer à la
suivante
D→B→A→C
A
foo
B
C
foo
D
Héritage multiple
Problème avec le « diamant »
A
foo
class A:
foo = 'A'
class B(A):
pass
class C(A):
foo = 'C'
class D(B, C):
pass
print(D.foo)
B
C
foo
D
# ???
Héritage multiple
Problème avec le « diamant ».
La recherche « depth first »
donne D.foo == A.foo,
alors que C a déjà « spécifié »
l'attribut foo.
Nouvelle règle : une classe est
toujours cherchée après toutes
ses classes dérivées.
D→B→C→A
A
foo
B
C
foo
D
Héritage multiple
A
foo
On peut toujours connaître le
« Method Resolution Order »
avec la méthode de classe .mro():
B
C
foo
D
>>> print(D.mro())
(<class '__main__.D'>, <class '__main__.B'>,
<class '__main__.C'>, <class '__main__.A'>,
<class 'object'>)
Polymorphisme
Polymorphisme
En Python, on s'intéresse aux méthodes implémentées par un objet et non pas à son « type »
Duck typing : « If it quacks like a duck, it's a duck »
class Chat:
def parle(self):
print('Miaou')
class Chien:
def parle(self):
print('Wof')
def f(x):
x.parle()
chat = Chat()
chien = Chien()
f(chat)
f(chien)
Polymorphisme
abstract class Animal {
public abstract void parle();
}
class Chat extends Animal {
@Override
public void parle() {
System.out.println("Miaou");
}
}
class Chien extends Animal {
@Override
public void parle() {
System.out.println("Wof");
}
}
Polymorphisme
public class Main {
static void f(Animal x) {
x.parle();
}
public static void main(String[] args) {
Animal chat = new Chat();
Animal chien = new Chien();
f(chat);
f(chien);
}
}
Polymorphisme
class Chat:
...
class Chien:
...
class Robot:
def parle(self):
print('Bonjour')
def f(x):
x.parle()
chat = Chat()
chien = Chien()
robot = Robot()
f(chat)
f(chien)
f(robot)
Polymorphisme
interface Parlant {
void parle();
}
abstract class Animal implements Parlant {
@Override
public abstract void parle();
}
class Robot implements Parlant {
@Override
public void parle() {
System.out.println("Bonjour");
}
}
Polymorphisme
public class Main {
static void f(Parlant x) {
x.parle();
}
public static void main(String[] args) {
Animal chat = new Chat();
Animal chien = new Chien();
Robot robot = new Robot() ;
f(chat);
f(chien);
f(robot);
}
}
Méthodes statiques et de classe
Méthodes statiques
Parfois on est intéressé à appeler des méthodes sans avoir une instance
particulière = méthodes statiques.
class Atome:
TP = ['H', 'He', 'Li', 'Be', 'B', 'C', 'N', 'O', 'F', Ne']
def __init__(self, np):
self.np = np
@staticmethod
def affiche_symbole(np):
print(TP[np - 1])
# pas de 'self' !
# On appelle la méthode sur la classe !
Atome.affiche_symbole(5)
Méthodes de classe
On peut avoir des méthodes qui en premier argument ont la classe elle-même au lieu d'une
instance particulière. Ces méthodes sont déclarées avec le décorateur @classmethod.
Les méthodes de classe sont très utiles pour créer de « factory methods ».
class Date:
def __init__(self, jour, mois, an):
self.jour = jour
self.mois = mois
self.an = an
@classmethod
def from_string(cls, s):
jour, mois, an = [int(x) for x in s.split('/')]
return cls(jour, mois, an)
d1 = Date(30, 12, 2000)
d2 = Date.from_string('30/12/2000')
Téléchargement
Explore flashcards