diff --git a/sessions/python-06.md b/sessions/python-06.md new file mode 100644 index 0000000..1093666 --- /dev/null +++ b/sessions/python-06.md @@ -0,0 +1,252 @@ +% Programmation avec Python (chapitre 6) +% Dimitri Merejkowsky + + +# + +\center \huge Les classes + +# Paradigmes + +Une façon d'envisager le code. +Pour l'instant on n'a vu que le paradigme *procédural* (ou (impératif). + +Il y en a plein d'autres! (*fonctionnel* notamment, dont on parlera un jour) + +# Détails du procédural + +* des types simples (entiers, booléens) +* des structures de données (dictionnaires, listes ...) +* des fonctions qui manipulent des types simples ou des structures +* les fonctions sont appelées les unes après les autres + +Aujourd'hui on va parler de *l'orienté objet*. + +# Un petit détour + +Un nouveau built-in: `id()` + +L'adresse de l'objet pointé par la variable: + +``` +>>> a = 42532 +>>> id(a) +94295009035968 +>>> b = a +>>> id(b) # même objet +94295009035968 +>>> c = 42532 # objet différent, même valeur +>>> id(c) +``` + +# Orienté objet - 1ère définition + +Mettre au même endroit: + +* des données +* des fonctions qui opèrent sur ces données + +L'important c'est que les deux aillent ensemble + +OOP en Anglais (ou juste OO) + +# Orienté objet - 2ème définition + +Des "cellules" qui s'envoient des "messages". + +Notamment, les cellules ne "voient" que leur état interne. + +On peut envoyer un message d'une cellule à une autre *sans* connaître +beaucoup de détails à propos du destinataire du message + +# Les classes + +On va parler *d'une* façon de faire de l'orienté objet: avec des classes. + +Mais notez bien qu'on peut faire de l'orienté objet *sans* classes! + +# Le plan de construction + +La seule chose dont on a besoin, c'est le mot-clé `class` et un nom. + +```python +class MyObject: + pas +``` + +La classe est le plan de construction de notre objet. + +# Créons des objets + +```python +>>> object_1 = MyObject() +>>> object_2 = MyObject() +``` + +Python ne sait rien de l'objet à part son adresse on mémoire et son nom: + +```python +print(object_1) + <__main__.MyObject at 0x7f52c831e2b0> +``` + +On appelle `object_1` et `object_2` des *instances* de la classe `MyObject`. + +# Méthodes + +Une fonction dans une classe + +``` +class MyObject: + def my_method(the_object): + print("hello", the_object) +``` + +C'est tout! + +# Méthodes - 2 + +La méthode n'existe pas en dehors de la classe (souvenez vous des cellules !) + +``` +>>> my_method() +NameError +>>> object = MyObject() +>>> object.my_method() +Hello, +``` + +Notez que `my_method` a pris en premier argument ce qu'il y avait *à gauche* du point: + +D'ailleurs, ce code fonctionne aussi et retourne *la même chose*: + +``` +>>> MyObject.my_method(object) +Hello, +``` + +# Méthodes - 3 + +Il *faut* passer l'objet en cours en paramètre: + +```python +class MyObject: + def broken(): + print("You cannot call me!") +``` + +```python +>>> o = MyObject() +>>> o.broken() +TypeError: broken() takes 0 positional arguments but 1 was given +``` + +# Conventions + +* Les classes sont en CamelCase +* Tout le reste (méthodes, etc...) en snake_case +* L'objet en cours s'appelle **toujours** `self` + + +```python +class MyObject: + def my_method(self): + print("hello", self) +``` + +# Attributs + +* Des variables dans un objet. +* On peut ajouter un attribut quand on veut à qui on veut, et toujours avec le + point au milieu: + +```python +>>> object = MyObject() +>>> object.attribute # ici l'attribut n'existe pas +AttributError +>>> object.attribute = 42 # maintenant oui +>>> object.attribute +42 +``` + +# Attributs dans les méthodes + +Avec `self`, bien sûr: + +```python +class MyObject: + def print_attribute(self): + print(self.attribute) + + def change_attribute(self, new_value) + self.attribute = new_value +``` + +# Accéder aux attributs + +```python +>>> object = MyObject() +>>> object.print_attribute() # ici l'attribut n'existe pas +AttributError +>>> object.attribute = 42 +>>> object.print_attribute() # ça marche +42 +>>> object.change_attribute(43) +>>> object.attribute +43 +``` + +# Initialisation des attributs + +Avec `__init__`: + +* méthode "spéciale" +* appelée automatiquement +* notez les deux underscores avant et après ('dunder' en Anglais) + +```python +class MyObject: + def __init__(self): + self.attribute = 42 +``` + +```python +>>> object = MyObject() +>>> object.attribute +42 +``` + +# Construire des objets différents + +`__init__()` et `MyObject()` sont des appels de fonctions comme les autres + +```python +class Car: + def __init__(self, color_to_use="black"): + self.color = color_to_use + +>>> ford = Car() +>>> ford.color +"black" +>>> ferrari = Car(color_to_use="red") +>>> ferrari.color +"red" +``` + +# Notes + +En vrai, on nomme souvent les paramètres du constructeur et les attributes de la même façon. + +```python +class Car: + def __init__(self, color="black"): + self.color = color +``` + +# Récapitulatif + +* Classe: plan de construction +* Object: ce qu'on crée avec le plan +* Instance: objet issue d'une classe +* Méthode: fonction dans une classe (qui prend `self` en premier argument) +* Attribut: variable dans un objet