From 9c793899ec67088508fb456ff2227f70d152d877 Mon Sep 17 00:00:00 2001 From: Dimitri Merejkowsky Date: Sat, 23 May 2020 14:06:26 +0200 Subject: [PATCH] Ajout du chapitre sur les objets --- .../01-attributs-et-instances-de-classes.rst | 107 +++++++++++++ cours/source/19-classes-04/02-objets.rst | 142 ++++++++++++++++++ cours/source/19-classes-04/index.rst | 16 ++ cours/source/index.rst | 1 + 4 files changed, 266 insertions(+) create mode 100644 cours/source/19-classes-04/01-attributs-et-instances-de-classes.rst create mode 100644 cours/source/19-classes-04/02-objets.rst create mode 100644 cours/source/19-classes-04/index.rst diff --git a/cours/source/19-classes-04/01-attributs-et-instances-de-classes.rst b/cours/source/19-classes-04/01-attributs-et-instances-de-classes.rst new file mode 100644 index 0000000..d11374e --- /dev/null +++ b/cours/source/19-classes-04/01-attributs-et-instances-de-classes.rst @@ -0,0 +1,107 @@ +Attributs et instances de classe +================================ + +Rappels +------- + +Voici un exemple de classe qui contient une méthode:: + + class MaClasse + def ma_méthode(self): + print(self.mon_attribut) + + +Le bloc indenté en-dessous du mot-clé ``class`` s'appelle le +*corps* de la classe. Et les méthodes sont définies avec le +mot-clé ``def`` dans le corps de la classe. + +On dit que ce sont des *méthodes d'instance* par ce qu'il +faut créer une instance pour pouvoir les appeler:: + + mon_instance = MaClasse() + mon_instance.ma_méthode() + + +Attributs de classes +--------------------- + +On peut également déclarer des variables dans le corps d'une classe. + +On crée ainsi des *attributs de classe*:: + + class MaClasse: + mon_attribut_de_classe = 42 + + +Ici ``mon_attribut_de_classe`` existe *à la fois* dans les instances de ``MaClasse`` +et dans la classe elle-même:: + + print(MaClasse.mon_attribut_de_classe) + # affiche 42 + mon_instance = MaClasse() + print(mon_instance.mon_attribut_de_classe) + # affiche 42 + + +Un point important est que les attributs de classe sont *partagés* entre +toutes les instances. Voici un exemple d'utilisation possible:: + + class Voiture: + nombre_total_de_voitures_fabriquées = 0 + + def __init__(self, marque, couleur): + print("Construction d'une", marque, couleur) + Voiture.nombre_total_de_voitures_fabriquées += 1 + + + ferrari_1 = Voiture("Ferrari", "rouge") + mercedes_1 = Voiture("Mercedes, "noire") + ferrari_2 = Voiture("Ferrari", "rouge") + print("total:", Voiture.nombre_total_de_voitures_fabriquées) + # Affiche: + # Construction d'une Ferrari rouge + # Construction d'une Mercedes noire + # Construction d'une Ferrari rouge + # total: 3 + +Notez que pour changer l'attribut de classe depuis une méthode, (comme dans le méthode +``__init__`` ci-dessus) on utilise le nom de la classe directement, et non pas ``self``. + +Méthodes de classes +-------------------- + +On peut aussi définir des méthodes de classes avec le décorateur `classmethod` + +Dans ce cas, le permier argument s'appelle ``cls`` et prend la valeur de la *classe* +elle-même. Pour poursuivre sur notre exemple:: + + class Voiture: + nombre_total_de_voitures_fabriquées = 0 + + def __init__(self, marque, couleur): + print("Construction d'une", marque, couleur) + Voiture.nombre_total_de_voitures_fabriquées += 1 + + @classmethod + def fabrique_ferrari(cls): + return cls("ferrari", "rouge") + + + ferrari = Voiture.fabrique_ferrari() + + +Détaillons ce qu'il se passe sur la dernière ligne: +à gauche du égal il y a une variable et à droite une expression(``Voiture.fabrique_ferrari()``) + +L'expression est constitué d'une classe à gauche du point (``Voiture``) et +d'un attribut à droite du point ``fabrique_ferrari`` suivi de parenthèses. + +Comme ``fabrique_ferrari`` est une méthode de classe, on va appeler la méthode +de classe ``fabrique_ferrari`` en lui passent la classe Courante en argument. + +On arrive ainsi dans le corps de la méthode de classe ``fabrique_ferrari``, et +``cls`` vaut la classe `Voiture`. + +Finalement, on évalue l'expression ``cls("ferrari", rouge")`` en remplaçant +``cls`` par sa valeur, ce qui donne ``Voiture("ferrari", "rouge")`` qui +correspond bien à ce qu'on obtient : une instance de la classe Voiture. diff --git a/cours/source/19-classes-04/02-objets.rst b/cours/source/19-classes-04/02-objets.rst new file mode 100644 index 0000000..b38b47d --- /dev/null +++ b/cours/source/19-classes-04/02-objets.rst @@ -0,0 +1,142 @@ +Objets +====== + + +En fait, *tout ce qu'on manipule en Python* est un objet. Et tous les objets sont +toujours des instances d'une classe - on peut accéder à la classe qui a servi +à instancier un objet avec la fonction ``type``, par exemple:: + + class MaClasse: + pass + + mon_instance = MaClasse() + print(type(mon_instance)) + # Affiche: + # + + +Mais aussi:: + + print(type(2)) + # affice: int + + print(type("bonjour")) + # affice: str + +Donc en Python, les entiers sont des instances de la classe ``int``, et les strings des instances de la +classe ``str``. + +Ainsi, vous pouvez voir l'expression ``x = str(y)`` de deux façons: + +* Soit on appelle la fonction native ``str`` pour convertir ``y`` en string + +* Soit on crée une nouvelle instance de la classe ``str`` en appelant le constructeur + de la classe ``str`` avec ``y`` en argument. + +Notez que ça ne s'arrète pas là:: + + def ma_fonction(): + pass + + print(type(ma_fonction)) + # affiche: function + + class MaClasse: + def ma_méthode(self): + pass + + mon_instance = MaClasse() + print(type(mon_instance.ma_méthode)) + # affiche: method + + import sys + print(type(sys)) + # affiche: module + + +Et même:: + + print(type(MaClasse)) + # affiche: type + + print(type(type)) + # affiche: type + +Et oui, les classes elles-mêmes sont des instances de classe! (la classe ``type``) + +Du coup en Python, le terme 'objet' désigne *toujours* une instance de classe - même +``None`` est une instance d'une classe (elle s'appelle ``NoneType``). + +Ordre de résolution +-------------------- + +Il est temps de revenir sur l'évaluation des expressions impliquant des +attributs. + +On a vu trois systèmes différents: + +Appeler une fonction définie dans un module:: + + import mon_module + mon_module.ma_fonction() + +Appeler une méthode d'instance définie dans une classe:: + + mon_instance = MaClasse() + mon_instance.ma_méthode() + +Appeler une méthode de classe définie dans une classe:: + + MaClasse.ma_méthod_de_classe() + +D'après ce qu'on a vu dans la section précédente, on sait maintenant que +dans tous les cas, à gauche du point se situe un objet, et que tous +les objets sont des instances d'une classe (appelé le "type" de l'objet). + +Pour évaluer l'expression ``mon_objet.mon_attribut``, où `mon_objet`` est une +instance de ``mon_type``, Python cherche toujours l'attribut dans deux endroits: + +* D'abord en tant qu'attribut de l'instance ``mon_objet`` +* Ensuite, en tant qu'attribut de la classe ``mon_type`` + +La recherche se poursuit ainsi en suivant toutes les classe parentes de +``mon_type``. + + +On peut voir ce mécanisme en action dans le code suivant:: + + class A: + def f1(self): + print("f1 dans A") + + def f2(self): + print("f2") + + + class B(A): + @classmethod + def f3(cls): + print("f3") + + def f1(self): + print("f1 dans B") + + + b = B() + b.f1() + b.f3() + b.f2() + # affiche: + # f1 dans B + # f3 + # f2 + + +Conclusion +------------ + +Maintenant vous devriez comprendre pourquoi on dit parfois qu'en +Python, **tout est objet**. + +Dans un prochain chapitre, on expliquera pourquoi en plus de cela +on peut dire qu'en Python, **tout est dictionnaire**. diff --git a/cours/source/19-classes-04/index.rst b/cours/source/19-classes-04/index.rst new file mode 100644 index 0000000..eb86b98 --- /dev/null +++ b/cours/source/19-classes-04/index.rst @@ -0,0 +1,16 @@ +Objets +====== + +On a déjà parlé de *programmation* orientée objet en Python, mais pour l'instant +on a vu que des classes et des instances. + +Or le concept d'objet existe bel et bien en Python, et il est plus que temps +de vous le présenter. + +Mais avant, il faut faire un petit détour par les attributs et méthodes de classes. + +.. toctree:: + :maxdepth: 1 + + ./01-attributs-et-instances-de-classes.rst + ./02-objets.rst diff --git a/cours/source/index.rst b/cours/source/index.rst index 4ea3feb..b904d3c 100644 --- a/cours/source/index.rst +++ b/cours/source/index.rst @@ -35,3 +35,4 @@ remarques. 16-classes-03/index.rst 17-décorateurs/index.rst 18-exceptions/index.rst + 19-classes-04/index.rst