% Programmation avec Python (chapitre 5) % Dimitri Merejkowsky
\center \huge Rappels sur les fonctions
# Définition d'une fonction sans arguments
def ma_fonction():
print("ma_fonction commence ...")
print("bonjour")
print("ma_fonction finit.")
# Appel de la fonction `ma_fonction`:
>>> ma_fonction()
ma_fonction commence ...
bonjour
ma_fonction finit.
# Définition d'une fonction avec un argument, x:
def ma_fonction(x):
print("x vaut", x)
# Appel de la fonction `ma_fonction`:
>>> ma_fonction(42)
x vaut 42
pass
En Python, à cause de l’organisation en blocs indentés, on ne peut pas vraiment avoir de blocs vides. Mais parfois, on a besoin d’un bloc qui ne fasse rien.
Dans ce cas, on peut utiliser le mot-clé pass
, par exemple
après un if:
une_condition = False
if une_condition:
pass
else:
print("une_condition n'est pas vraie")
pass
- 2On peut aussi - et c’est l’usage le plus courant - utiliser pass
pour
définir une fonction qui ne fait rien:
def ne_fait_rien():
pass
>>> ne_fait_rien()
<rien>
Ce qu’on a vu jusqu’ici:
On appelle cet ensemble de concepts, cette façon d'écrire du code, un paradigme - et c’est un paradigme procédural.
On va passer à un autre paradigme: l’orienté objet.
Un “objet” informatique représente un véritable “objet” physique dans le vrai monde véritable.
Ce n’est pas une très bonne définition:
Je le mentionne juste parce que c’est une idée reçue très répandue.
Une meilleure définition, c’est de dire que la programmation orientée objet permet de mettre au même endroit:
L’important c’est que les deux aillent ensemble!
\vfill
Note: ce n’est pas la meilleure définition de l’orienté objet, mais on s’en contentera pour le moment ...
On va parler d’une façon de faire de l’orienté objet: avec des classes et des instances.
Mais notez bien qu’on peut faire de l’orienté objet sans classes!
Pour construire un objet en Python, on a besoin d’un plan de construction.
On appelle ce plan une classe et on la définit ainsi:
class MaClasse:
# du code ici
Comme les fonctions, les classes contiennent un corps, qui est le bloc identé en dessous
du mot-clé class
, de nom de la classe et du :
en fin de ligne
On peut faire un plan de construction vide avec le mot clé pass:
class MaClasse:
pass
Dans ce cas, on crée une instance en écrivant le nom de la classe suivi d’une paire de parenthèses - un peu comme pour appeler une fonction:
>>> mon_instance = MaClasse()
Ici, mon_instance
est une instance de la classe MaClasse
.
Les attributs sont des éléments nommés à l’intérieur d’une instance.
On peut y accéder avec la syntaxe <instance>.<attribut>
:
y = a.x
Ici, y
est une variable qui a la valeur de l’attribut x
de l’instance a
.
Les attributs peuvent être des fonctions:
func = a.x
func(10)
Ici, on crée une variable func
qui prend la valeur de l’attribut x
dans l’instance a
, puis
on l’appelle avec l’argument 10
à la ligne suivante.
Le code suivant fait exactement la même chose, mais avec une ligne de moins:
a.x(10)
On a déjà vu des attributs, quand on a utilisé des modules
import random
nombre_au_hasard = random.randint(0, 10)
Ici, random
est un module, et randint
est un attribut du module random
. Il se trouve
que cet attribut est une fonction qu’on peut appeler avec deux arguments.
On reviendra sur les modules dans un prochain chapitre.
On peut créer des attributs dans n’importe quel instance, en utilisant l’assignation:
>>> mon_instance = MaClasse()
# Création de l'attribut `x` dans `mon_instance`
>>> mon_instance.x = 42
# Accès à l'attribut `x` dans `mon_instance`
>>> mon_instance.mon_attribut
42
On peut aussi mettre des méthodes dans des classes.
On utilise def
, comme pour les fonctions, mais les méthodes doivent avoir au
moins un argument appelé self
, et être à l’intérieur du bloc de la classe:
class MaClasse:
def ma_méthode(self):
return 42
Une méthode ne peut être appelée que depuis une instance:
class MaClasse:
def ma_méthode(self):
return 42
>>> ma_méthode()
Erreur
>>> mon_instance = MaClasse()
>>> mon_instance.ma_méthode()
42
Notez qu’on ne passe pas d’argument quand on appelle ma_méthode
depuis l’instance de la classe.
self
prend la valeur de l’instance courante quand la méthode est appelée.
On peut le voir en utilisant des attributs:
class MaClasse:
def affiche_attribut_x(self):
# Accès à l'attribut `x` dans `self`
print(self.x)
>>> mon_instance = MaClasse()
>>> mon_instance.x = 42
>>> mon_instance.affiche_attribut_x()
42
On peut aussi créer des attributs dans une méthode:
class MaClasse:
def crée_attribut_x(self):
self.x = 42
def affiche_attribut_x(self):
print(self.x)
>>> mon_instance = MaClasse()
>>> mon_instance.affiche_attribut_x()
# Erreur: `mon_instance` n'a pas d'attribut `x`
>>> mon_instance.crée_attribut_x()
>>> mon_instance.affiche_attribut_x()
42
Les méthodes peuvent aussi prendre plusieurs arguments, en plus de self
- mais self
doit
toujours être le premier argument.
Par exemple, pour créer un attribut avec une certaine valeur:
class MaClasse
def crée_attribut_x(self, valeur_de_x):
self.x = valeur_de_x
def affiche_attribut_x(self);
print(self.x)
>>> mon_instance = MaClasse()
>>> mon_instance.crée_attribut_x(42)
>>> mon_instance.affiche_attribut_x()
42
Comme les méthodes sont aussi des attributs, les méthodes d’une classe peuvent s’appeler les unes les autres:
class MaClasse:
def méthode_1(self):
print("démarrage de la méthode 1")
print("la méthode 1 affiche bonjour")
print("bonjour")
print("fin de la méthode 1")
def méthode_2(self):
print("la méthode 2 appelle la méthode 1")
self.méthode_1()
print("fin de la méthode 2")
>>> mon_instance = MaClasse()
>>> mon_instance.méthode_2()
la méthode 2 appelle la méthode 1
démarrage de la méthode 1
la méthode 1 affiche bonjour
bonjour
fin de la méthode 1
fin de la méthode 2
Si vous définissez une méthode __init__
, celle-ci est appelée automatiquement
quand l’instance est construite.
On dit que c’est une méthode “magique” parce qu’elle fait quelque chose sans qu’on l’appelle explicitement.
On utilise souvent __init__
pour créer des attributs
class MaClasse:
def __init__(self):
self.x = 1
self.y = 2
>>> mon_instance = MaClasse()
# __init__ est appelée automatiquement!
>>> mon_instance.x
1
>>> mon_instance.y
2
On prend souvent les valeurs des attributs à créer en arguments de la méthode __init__
.
class MaClasse:
def __init__(self, x, y):
self.x = x
self.y = y
Dans ce cas, les arguments de la méthode __init__
apparaissent à l’intérieur des parenthèses après le
nom de la classe:
>>> mon_instance = MaClasse(3, 4)
>>> mon_instance.x
3
>>> mon_instance.y
4
D’où le nom: __init__
sert a initialiser les attributs de la classe.
Note: on appelle parfois la méthode __init__
un constructeur, un terme qui est employé pour d’autres langages qui utilisent également des classes, comme Java ou C++.
Mais c’est un abus de langage: __init__
en Python ne construit rien!
self
en premier argument)__init__
: méthode magique appelée automatiquement pendant l’instanciationAinsi, on peut ranger au même endroit des données et des fonctions opérant sur ces données.
Les données sont les attributs, et les fonctions opérant sur ces attributs sont les méthodes.
On peut ainsi séparer les responsabilités à l’intérieur d’un code en les répartissant entres plusieurs classes.
Définition: cacher à l’utilisateur de la classe certains détails du fonctionnement de celle-ci.
On parle souvent d’opposition entre code public, utilisable à l’extérieur, de la classe, et code privé, utilisé à l’intérieur de la classe.
Ou encore d’interface et de d’implémentation.
class MaClasse:
def __init__(self):
# Notez le tiret bas en début
# du nom de l'attribut
self._mon_attribut_privé = ...
def ma_méthode_publique(self):
return self._mon_attribut_privé
>>> mon_objet = MaClasse()
>>> mon_objet.ma_méthode_publique()
Notez que rien ne vous empêche d'écrire:
>>> mon_objet= MaClasse()
>>> mon_objet._mon_attribut_privé = "une-autre-valeur"
mais alors vous n'êtes plus dans le cas d’usage prévu par l’auteur de la classe MaClasse.
Si _mon_attribut_privé
demande de longs calculs, on peut envisager de stocker le résultat
de façon à ce que le deuxième appel à ma_méthode_publique()
soit plus rapide.
De l’extérieur, l’appel à ma_méthode_publique()
sera “magiquement” plus rapide la deuxième
fois :)
class MaClasse:
def __init__(self):
self._mon_attribut_privé = None
def ma_méthode_publique(self):
if self._mon_attribut_privé is None:
self._mon_attribut_privé = gros_calcul()
else:
return self._mon_attribut_privé
>>> mon_objet = MaClasse()
>>> mon_objet.ma_méthode_publique()
# gros_calcul() est appelée
>>> mon_objet.ma_méthode_publique()
# retourne une valeur immédiatement!
\center \huge QCM
def dire_bonjour():
return "Bonjour"
dire_bonjour()
\pause
Réponse: 3: la fonction retourne quelque chose, mais on n’en fait rien
def différence(x, y):
return x - y
z = différence(y=4, x=5)
Que vaut z
?
1
-1
\pause
Réponse: 1 Quand on nomme les arguments, on les mets dans l’ordre qu’on veut.
class MaClasse:
def ma_méthode():
print("Bonjour")
mon_objet = MaClasse()
mon_objet.ma_méthode()
\pause
Réponse 1: les méthodes prennent self
en premier argument
class MaClasse:
def ma_méthode(self):
print("mon attribut est", self.mon_attribut)
mon_attribut = 42
mon_objet = MaClasse()
mon_objet.ma_méthode()
\pause
Réponse 2: Les attributs doivent exister quand ils sont utilisés comme valeur
class MaClasse:
def ma_méthode(self):
print(self.mon_attribut)
mon_objet = MaClasse()
mon_objet.mon_attribut = 42
mon_objet.ma_méthode()
\pause
Réponse 2: On peut créer des attributs avec des assignations
class MaClasse:
def ma_méthode(self):
self.mon_attribut = 42
print("mon attribut est", self.mon_attribut)
mon_objet = MaClasse()
mon_objet.ma_méthode()
\pause
Réponse 1: On peut créer des attributs dans
des méthodes grâce à self
.
class MaClasse:
def __init__(self, valeur):
self.mon_attribut = valeur
mon_objet = MaClasse()
valeur = mon_objet.mon_attribut
print(valeur)
\pause
Réponse 1: __init__
est une méthode magique appelée automatiquement,
donc il faut passer un argument quand on instancie la classe: mon_objet = MaClasse(42)
\center \huge Atelier
Vous êtes développeur dans une usine de fabrication de robots.
RX837
ou BC811
robot.py
, à récupérer sur git.e2li.org
main()
de test - à vous d’implémenter la classe!