diff --git a/saison-2/sessions/python-S02-E05.md b/saison-2/sessions/python-S02-E05.md index d51e5ba..9ec03b7 100644 --- a/saison-2/sessions/python-S02-E05.md +++ b/saison-2/sessions/python-S02-E05.md @@ -73,7 +73,7 @@ Ce qu'on a vu jusqu’ici: * Des types simples (entiers, booléens, ...) * Des structures de données (listes, dictionnaires, ...) -* Des fonctions qui manipulent ces types ou ces types +* Des fonctions qui manipulent ces données ou ces types * Des fonctions qui s’appellent les unes les autres On appelle cet ensemble de concepts, cette façon d'écrire du code, un *paradigme* - @@ -109,9 +109,9 @@ L'important c'est que les deux aillent ensemble! pour le moment ...* -# Les classes +# Classes et instances -On va parler *d'une* façon de faire de l'orienté objet: avec des classes. +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! @@ -122,42 +122,42 @@ 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: ```python -class MonObjet: +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 -# Créons des objets +# Créons des instances On peut faire un plan de construction vide avec le mot clé pass: ```python -class MonObjet: +class MaClasse: pass ``` -Dans ce cas, on crée un objet en mettant le nom de la classe suivi d'une paire de parenthèses - +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: ```python ->>> objet_1 = MonObjet() +>>> mon_instance = MaClasse() ``` -Ici, `objet_1` est une *instance* de la classe `MonObjet`. +Ici, `mon_instance` est une *instance* de la classe `MaClasse`. # Attributs -Les attributs sont des éléments **nommés** à *l'intérieur* d'un objet. +Les attributs sont des éléments **nommés** à *l'intérieur* d'une instance. -On peut y accéder avec la syntaxe `.`: +On peut y accéder avec la syntaxe `.`: ```python y = a.x ``` -Ici, `y` est l'attribut `x` de l'objet `a`. +Ici, `y` est une variable qui a la valeur de l'attribut `x` de l'instance `a`. # Attributs - 2 @@ -168,7 +168,7 @@ func = a.x func(10) ``` -Ici, on crée une variable `func` qui prend la valeur de l'attribut `x` dans l'objet `a`, puis +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: @@ -194,10 +194,10 @@ On reviendra sur les modules dans un prochain chapitre. # Attributs - 4 -On peut *créer* des attributs dans *n'importe quel objet*, en utilisant l'*assignation*: +On peut *créer* des attributs dans *n'importe quel instance*, en utilisant l'*assignation*: ```python ->>> mon_instance = MonObjet() +>>> mon_instance = MaClasse() # Création de l'attribut `x` dans `mon_instance` >>> mon_instance.x = 42 @@ -215,29 +215,28 @@ On utilise `def`, comme pour les fonctions, mais les méthodes *doivent* avoir a moins un argument appelé `self`, et être à l'intérieur du bloc de la classe: ```python -class MonObjet: +class MaClasse: def ma_méthode(self): return 42 ``` # Méthodes - appel -Une méthode ne peut être appelée que depuis une *instance* de -l'objet: +Une méthode ne peut être appelée que depuis une *instance*: ```python -class MonObjet: +class MaClasse: def ma_méthode(self): return 42 >>> ma_méthode() Erreur ->>> mon_instance = MonObjet() +>>> 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 l'objet. +Notez qu'on ne passe *pas* d'argument quand on appelle `ma_méthode` depuis l'instance de la classe. # Méthodes et attributs - 1 @@ -247,13 +246,13 @@ Notez qu'on ne passe *pas* d'argument quand on appelle `ma_méthode` depuis l'in On peut le voir en utilisant des attributs: ```python -class MonObjet: +class MaClasse: def affiche_attribut_x(self): # Accès à l'attribut `x` dans `self` print(self.x) ->>> mon_instance = MonObjet() +>>> mon_instance = MaClasse() >>> mon_instance.x = 42 >>> mon_instance.affiche_attribut_x() 42 @@ -264,13 +263,13 @@ class MonObjet: On peut aussi *créer* des attributs dans une méthode: ```python -class MonObjet: +class MaClasse: def crée_attribut_x(self): self.x = 42 def affiche_attribut_x(self): print(self.x) ->>> mon_instance = MonObjet() +>>> mon_instance = MaClasse() >>> mon_instance.affiche_attribut_x() # Erreur: `mon_instance` n'a pas d'attribut `x` @@ -288,14 +287,14 @@ Par exemple, pour créer un attribut avec une certaine valeur: ```python -class MonObjet +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 = MonObjet() +>>> mon_instance = MaClasse() >>> mon_instance.crée_attribut_x(42) >>> mon_instance.affiche_attribut_x() 42 @@ -303,11 +302,11 @@ class MonObjet # Méthodes appelant d'autres méthodes - 1 -Comme les méthodes sont *aussi* des attributs, les méthodes d'un objet peuvent s'appeler +Comme les méthodes sont *aussi* des attributs, les méthodes d'une classe peuvent s'appeler les unes les autres: ```python -class MonObjet: +class MaClasse: def méthode_1(self): print("démarrage de la méthode 1") print("la méthode 1 affiche bonjour") @@ -324,7 +323,7 @@ class MonObjet: # Méthodes appelant d'autres méthodes - 2 ```python ->>> mon_instance = MonObjet() +>>> mon_instance = MaClasse() >>> mon_instance.méthode_2() ``` @@ -340,7 +339,7 @@ fin de la méthode 2 # Une méthode spéciale Si vous définissez une méthode `__init__`, celle-ci est appelée *automatiquement* -quand l'objet est construit. +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. @@ -351,12 +350,12 @@ On utilise souvent `__init__` pour créer des attributs ```python -class MonObjet: +class MaClasse: def __init__(self): self.x = 1 self.y = 2 ->>> mon_instance = MonObjet() +>>> mon_instance = MaClasse() # __init__ est appelée automatiquement! >>> mon_instance.x @@ -370,7 +369,7 @@ class MonObjet: On prend souvent les *valeurs* des attributs à créer en arguments de la méthode `__init__ `. ```python -class MonObjet: +class MaClasse: def __init__(self, x, y): self.x = x self.y = y @@ -380,21 +379,26 @@ Dans ce cas, les arguments de la méthode `__init__` apparaissent à l'intérieu nom de la classe: ``` ->>> mon_instance = MonObjet(3, 4) +>>> mon_instance = MaClasse(3, 4) >>> mon_instance.x 3 >>> mon_instance.y 4 ``` -*Pour cette raison, `__init__` est souvent appelé le _constructeur_ de la classe.* +D'où le nom: `__init__` sert a initialiser les attributs de la classe. + +# Constructeurs + +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! # Récapitulatif * Classe: plan de construction -* Objet: ce qu'on crée avec le plan -* Attribut: variable dans un objet -* Instance: objet issue d'une classe +* Instance: ce qu'on construit avec une classe +* Attribut: variable dans une instance * Méthode: fonction dans une classe (qui prend `self` en premier argument) * `__init__`: méthode magique appelée automatiquement pendant l'instanciation @@ -421,7 +425,7 @@ Ou encore *d'interface* et de *d'implémentation*. # Exemple ```python -class MonObject: +class MaClasse: def __init__(self): # Notez le tiret bas en début # du nom de l'attribut @@ -430,7 +434,7 @@ class MonObject: def ma_méthode_publique(self): return self._mon_attribut_privé ->>> mon_objet = MonObject() +>>> mon_objet = MaClasse() >>> mon_objet.ma_méthode_publique() ``` @@ -439,12 +443,12 @@ class MonObject: Notez que rien ne vous empêche d'écrire: ```python ->>> mon_objet= MonObjet() +>>> 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 MonObjet. +par l'auteur de la classe MaClasse. # Exemple d'usage - 1 @@ -457,7 +461,7 @@ fois :) # Exemple d'usage - 2 ```python -class MonObject: +class MaClasse: def __init__(self): self._mon_attribut_privé = None @@ -467,7 +471,7 @@ class MonObject: else: return self._mon_attribut_privé ->>> mon_objet = MonObject() +>>> mon_objet = MaClasse() >>> mon_objet.ma_méthode_publique() # gros_calcul() est appelée >>> mon_objet.ma_méthode_publique() @@ -499,7 +503,7 @@ mais on n'en fait rien # ```python -def différencernce(x, y): +def différence(x, y): return x - y z = différence(y=4, x=5) @@ -518,11 +522,11 @@ Réponse: 1 Quand on nomme les arguments, on les mets dans l'ordre qu'on veut. # ```python -class MonObject: +class MaClasse: def ma_méthode(): print("Bonjour") -mon_objet = MonObject() +mon_objet = MaClasse() mon_objet.ma_méthode() ``` @@ -536,12 +540,12 @@ Réponse 1: les méthodes prennent `self` en premier argument # ```python -class MonObject: - def ma_méthode(): +class MaClasse: + def ma_méthode(self): print("mon attribut est", self.mon_attribut) mon_attribut = 42 -mon_objet = MonObject() +mon_objet = MaClasse() mon_objet.ma_méthode() ``` @@ -555,11 +559,11 @@ Réponse 2: Les attributs doivent exister quand ils sont utilisés comme valeur # ```python -class MonObject: +class MaClasse: def ma_méthode(self): print(self.mon_attribut) -mon_objet = MonObject() +mon_objet = MaClasse() mon_objet.mon_attribut = 42 mon_objet.ma_méthode() ``` @@ -574,12 +578,12 @@ Réponse 2: On peut créer des attributs avec des assignations # ```python -class MonObject: +class MaClasse: def ma_méthode(self): self.mon_attribut = 42 print("mon attribut est", self.mon_attribut) -mon_objet = MonObject() +mon_objet = MaClasse() mon_objet.ma_méthode() ``` @@ -594,11 +598,11 @@ des méthodes grâce à `self`. # ```python -class MonObject: +class MaClasse: def __init__(self, valeur): self.mon_attribut = valeur -mon_objet = MonObject() +mon_objet = MaClasse() valeur = mon_objet.mon_attribut print(valeur) ``` @@ -608,7 +612,8 @@ print(valeur) \pause -Réponse 2: `__init__` est une méthode magique appelée automatiquement. +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)` # @@ -629,9 +634,3 @@ Vous êtes développeur dans une usine de fabrication de robots. * Un squelette `robot.py`, à récupérer sur `git.e2li.org` * Contient déjà le `main()` de test - à vous d'implémenter la classe! - - -# Pour aller plus loin - -* Le robot n'a pas le droit d'avoir deux fois le même nom. À vous de coder cela! -