nsi:terminales:classes
Différences
Ci-dessous, les différences entre deux révisions de la page.
| Les deux révisions précédentesRévision précédenteProchaine révision | Révision précédente | ||
| nsi:terminales:classes [2021/06/23 18:00] – goupillwiki | nsi:terminales:classes [2022/08/29 21:39] (Version actuelle) – goupillwiki | ||
|---|---|---|---|
| Ligne 1: | Ligne 1: | ||
| ====== Classes - Programmation orientée objet (POO) ====== | ====== Classes - Programmation orientée objet (POO) ====== | ||
| - | {{: | + | {{nsi: |
| - | {{ : | + | {{ nsi: |
| + | |||
| + | {{ : | ||
| Apparu en 1960 avec LISP. Très répandu aujourd' | Apparu en 1960 avec LISP. Très répandu aujourd' | ||
| Ligne 25: | Ligne 27: | ||
| </ | </ | ||
| - | Pour le dire simplement, la POO permet | + | Dans l' |
| + | |||
| + | * Pas de façon simple pour regrouper toutes les données concernant | ||
| + | * pas de façon simple de savoir qu'une variable contient un triangle, et un triangle bien formé, | ||
| + | * multiplication de fonctions en vrac. | ||
| + | |||
| + | Les classes vont permettre de simplifier ces problèmes : | ||
| + | |||
| + | * La classe définit un modèle qui définit | ||
| + | * Dès lors qu'un objet est de type '' | ||
| + | * Chaque classe définit ses propres méthodes | ||
| ===== Notion de classe ===== | ===== Notion de classe ===== | ||
| Ligne 35: | Ligne 47: | ||
| <WRAP tip> | <WRAP tip> | ||
| - | Cela rappelle la définition abstraite des structures de données -- [[liste_abstraite|Listes]], | + | Cela rappelle la définition abstraite des structures de données -- [[.structures: |
| </ | </ | ||
| - | ===== Exercice : Exemple d'un module de géométrie | + | ===== Définir une classe |
| - | On souhaite faire des calculs de géométrie en 2D. Les points sont identifiés par leur coordonnées '' | + | ==== Donner |
| - | === Triangle === | + | Une classe est identifiée par un nom. L' |
| - | On souhaite travailler avec sur des triangles qui seront définies par les coordonnées de leurs 3 sommets et leur nom. | + | Par exemple : '' |
| - | - Sous quel forme représenter le triangle dans le code ? | + | ==== Identifier les attributs ==== |
| - | - Donner la signature d'une fonction chargée de calculer l'aire d'un tel triangle. | + | |
| - | - Est-il possible de mal utiliser la fonction, c'est à dire de l' | + | |
| - | === Parallélogramme === | + | Qu'est ce qui définit un objet ? |
| - | On poursuit en ajoutant des parallélogrammes. Même principe avec quatre | + | Un triangle sera défini par ses 3 sommets. Ses attributs seront donc ces sommets. |
| + | * 6 variables pour les 3 paires de coordonnées ? | ||
| + | * un tableau contenant les 3 paires de coordonnées ? | ||
| + | * 3 objets '' | ||
| - | - Peut-on choisir les sommets comme on veut ? Que faut-il vérifier ? | + | On a le choix. |
| - | - Donner la signature d'une fonction chargée de calculer l'aire d'un parallélogramme. | + | |
| - | === Et encore... | + | ==== Définir l' |
| - | On souhaite poursuivre en ajoutant d'autres formes : losanges, rectangles, hexagones... et ajouter d' | + | Comment agit on sur un objet depuis l'extérieur ? |
| - | Quel problème rencontre-t-on ? | + | On doit bien sûr pouvoir le créer. Un objet aura toujours un **constructeur** qui est une méthode spéciale permettant de le créer |
| - | ## Définir une classe | + | Et puis par exemple, pour un '' |
| - | Dans l' | + | ==== Choisir la visibilité ==== |
| - | * Pas de façon simple pour regrouper toutes | + | <WRAP group> |
| - | * pas de façon simple de savoir qu'une variable contient un triangle, et un triangle bien formé, | + | <WRAP half column> |
| - | * multiplication | + | En général, les classes permettent |
| - | Les classes vont permettre de simplifier ces problèmes : | + | Un élément accessible est dit **public**, s'il est inaccessible, |
| - | * La classe définit un modèle qui définit la façon de créer et d' | + | ==== Diagramme UML ==== |
| - | * Dès lors qu'un objet est de type `Triangle`, on est certain qu'il respecte les contraintes qu'on a fixé dans la classe. | + | {{nsi: |
| - | * Chaque classe définit ses propres fonctions | + | Pour aider au développement et au travail |
| - | ### Comment procéder | + | C'est un vaste domaine, nous allons rester simples. |
| - | *Remarque :* par convention, le nom d'une classe utilise *CamelCase* : première lettre en majuscule, majuscule à chaque changement de mot : `Triangle`, `TriangleIsocele`... | + | > Les + signifient " |
| - | + | </ | |
| - | On peut suivre les étapes suivantes : | + | <WRAP half column> |
| - | * Identifier les objets et leurs **attributs** : quelles sont les données caractérisant les objets | + | ^ |
| - | * Identifier les opérations : comment utilise-t-on l' | + | |
| - | * Définir la **visibilité** : quels attributs / méthodes sont visibles par les autres ? | + | |
| - | * Implémentation | + | |
| - | + | ||
| - | *On reviendra plus tard sur la notion de visibilité.* | + | |
| - | + | ||
| - | ### Exercice 2 | + | |
| - | + | ||
| - | Reprenons le cas du triangle. | + | |
| - | + | ||
| - | * Quels sont ses attributs ? | + | |
| - | * Quelles sont les opérations possibles ? | + | |
| - | + | ||
| - | Pour représenter ces choix de façons claire et explicite, on utilise | + | |
| - | + | ||
| - | | | + | |
| - | |: | + | |
| |**Attributs**| | |**Attributs**| | ||
| | + réel : x1 | | | + réel : x1 | | ||
| Ligne 114: | Ligne 109: | ||
| | + réel : aire() | | | + réel : aire() | | ||
| | + réel : périmètre() | | | + réel : périmètre() | | ||
| + | |||
| + | //diagramme UML// | ||
| + | </ | ||
| + | </ | ||
| Dans un programme complexe, le diagramme UML permettra d' | Dans un programme complexe, le diagramme UML permettra d' | ||
| - | ## Classe en Python | + | ==== Dépendance ==== |
| - | + | ||
| - | Voici un modèle | + | |
| - | </ | + | |
| - | + | ||
| - | <file python triangle.py> | + | |
| - | class Triangle: # on utilise PascalCase | + | |
| - | """ | + | |
| - | Commentaires utiles pour la lisibilité et la documentation | + | |
| - | """ | + | |
| - | x1: float # ceci n'est pas requis en Python | + | |
| - | y1: float # mais peut rendre le code plus clair | + | |
| - | x2: float | + | |
| - | y2: float | + | |
| - | x3: float | + | |
| - | y3: float | + | |
| - | nom: string | + | |
| - | + | ||
| - | def __init__(self, | + | |
| - | """ | + | |
| - | Constructeur - Gère l' | + | |
| - | """ | + | |
| - | self.x1 | + | |
| - | # self.x1 est l' | + | |
| - | self.y1 | + | |
| - | # etc. | + | |
| - | + | ||
| - | def aire(self) -> float : | + | |
| - | """ | + | |
| - | Documentation... | + | |
| - | -> float n'est pas requis en Python. Il permet seulement de préciser ce qui est | + | |
| - | attendu en sortie. | + | |
| - | """ | + | |
| - | + | ||
| - | # formule de maths... | + | |
| - | return abs((self.x2 - self.x1)*(self.y3 - self.y1) - (self.y2 - self.y1)*self(x3 - self.x1))/ | + | |
| - | + | ||
| - | # puis les autres méthodes... | + | |
| - | </ | + | |
| - | + | ||
| - | < | + | |
| - | **Exemple d' | + | |
| - | + | ||
| - | ```python | + | |
| - | monTriangle | + | |
| - | monTriangle.aire() # retourne 7.0 | + | |
| - | type(monTriangle) | + | |
| - | ``` | + | |
| - | + | ||
| - | ### Instanciation | + | |
| - | + | ||
| - | `Parallelogramme` et `Triangle` sont des modèles. Quand on définit la *classe* `Triangle`, on ne crée aucun objet de type `Triangle`. On se contente de dire comment faire pour en créer un ou pour l' | + | |
| - | + | ||
| - | Quand on écrit `monTriangle = Triangle(...)`, | + | |
| - | + | ||
| - | On dit que `monTriangle` est une **instance** de la classe `Triangle`. | + | |
| - | + | ||
| - | > **Autrement dit :** On peut définir ce qu'est une voiture et comment on fait une voiture dans un livre. Ce livre n'en est pas pour autant une voiture. Quand on suit le livre et qu'on fabrique la voiture, on obtient une réalisation de voiture, c'est une **instance** de voiture. | + | |
| - | + | ||
| - | Une classe peut avoir plusieurs instances : on peut créer plusieurs objets `Triangle` en suivant le guide que constitue la classe `Triangle`. | + | |
| - | + | ||
| - | > **Autrement dit :** On peut fabriquer plusieurs voitures, identiques ou pas. | + | |
| - | + | ||
| - | ### Exercice 3 | + | |
| - | + | ||
| - | * Dans un fichier `triangle.py` définissez la classe `Triangle` - **complétez** ce qui manque dans le modèle donné plus haut. | + | |
| - | * En fin de fichier, ajoutez le code de test suivant et exécutez : | + | |
| - | + | ||
| - | ```python | + | |
| - | if __name__ == ' | + | |
| - | monTriangle = Triangle(0, | + | |
| - | a = monTriangle.aire() | + | |
| - | p = monTriangle.perimetre() | + | |
| - | + | ||
| - | print(" | + | |
| - | print(" | + | |
| - | ``` | + | |
| - | + | ||
| - | ### Très important : | + | |
| - | + | ||
| - | * L' | + | |
| - | + | ||
| - | En Python, il s'agit de la méthode `__init__(...)` | + | |
| - | + | ||
| - | * En tant qu' | + | |
| - | * `monTriangle.x1` désigne l' | + | |
| - | * `monTriangle.aire` désigne la méthode `aire` de `monTriangle`. | + | |
| - | + | ||
| - | * Dans la signature et le corps de la méthode `aire`, on peut voire apparaître le mot-clé `self`. | + | |
| - | La méthode `aire` ne peut être appelée que via une **instance**, | + | |
| - | + | ||
| - | ```python | + | |
| - | tA.aire() # dans ce cas, self = tA | + | |
| - | tB.aire() # dans ce cas, self = tB | + | |
| - | ``` | + | |
| - | + | ||
| - | D' | + | |
| - | + | ||
| - | * En Python, **lors de la définition** de la méthode `aire`, on est obligé de préciser l' | + | |
| - | + | ||
| - | Au moment de l' | + | |
| - | + | ||
| - | #### L' | + | |
| - | Sans classe, on faisant `aireTriangle(triangle)` où `triangle` subissait la fonction passivement. | + | |
| - | + | ||
| - | Maintenant, `triangle` est un objet doté de méthodes et on écrit `triangle.aire()`. L' | + | |
| - | + | ||
| - | Chaque type d' | + | |
| - | + | ||
| - | ### Exercice 4 | + | |
| - | + | ||
| - | On peut considérer que le diagramme UML de la classe `Parallelogramme` est identique à ceci près qu'il faut ajouter un quatrième point. | + | |
| - | + | ||
| - | * Dans un fichier `parallelogramme.py` créez une classe `Parallelogramme` | + | |
| - | * En fin de fichier, ajoutez le code de test suivant et exécutez : | + | |
| - | + | ||
| - | ```python | + | |
| - | if __name__ == ' | + | |
| - | monPlg = Parallelogramme(0, | + | |
| - | a = monPlg.aire() | + | |
| - | p = monPlg.perimetre() | + | |
| - | + | ||
| - | print(" | + | |
| - | print(" | + | |
| - | ``` | + | |
| - | + | ||
| - | *On peut voir ici que le code est presque identique à celui du cas `Triangle`. Quand on appelle la méthode `aire()`, aucune confusion n'est possible. `monPlg` est un objet `Parallelogramme`, | + | |
| - | + | ||
| - | * Que faudrait-il faire pour être certain qu'un objet `Paralllelogramme` soit toujours valide ? | + | |
| - | + | ||
| - | *Comprendre : comment vérifier qu'il est valide au moment où on le crée et vérifier qu'il reste valide dans le cas où on modifie ses attributs.* | + | |
| - | + | ||
| - | #### Public / privé | + | |
| - | + | ||
| - | ```python | + | |
| - | plg = Parallelogramme(0, | + | |
| - | plg.x1 = 10 | + | |
| - | ``` | + | |
| - | + | ||
| - | Lors de la création `plg` est bien valide. Mais on modifie `plg.x1` de sorte qu'il ne l'est plus... | + | |
| - | + | ||
| - | Une solution est d' | + | |
| - | + | ||
| - | Un attribut **privé** ne peut-être lu et modifié que depuis l' | + | |
| - | + | ||
| - | *Remarque : En Python, il n'y a pas vraiment de gestion de l' | + | |
| - | + | ||
| - | Dans l' | + | |
| - | + | ||
| - | Dans le diagramme UML, on mettra - au lieu de +. | + | |
| - | + | ||
| - | *Remarque : Certains invitent à utiliser `__` (deux underscore au lieu d'un). Ne vous y fiez pas trop. Ce choix crée des difficultés et ne constitue pas une protection.* | + | |
| - | + | ||
| - | *La notion public / privé n'est pas explicite dans le programme. Ne vous en souciez donc pas trop, on pourra travailler en ne considérant que rien n'est privé.* | + | |
| - | + | ||
| - | ### Classes et sous-classes | + | |
| - | + | ||
| - | * **Éviter tout bloc de code trop compliqué | + | |
| - | * **Idem pour les classes | + | |
| - | + | ||
| - | ### Exercice 5 | + | |
| - | + | ||
| - | * Dans un fichier `point.py`, définir une classe `Point` ayant les attributs `x`, `y`. | + | |
| - | * Ajouter la méthode `distance(self, | + | |
| - | * Modifier les classes `Triangle` et `Parallelogramme` pour qu' | + | |
| - | + | ||
| - | + | ||
| - | ### Important | + | |
| - | ```python | + | |
| - | >>> | + | |
| - | >>> | + | |
| - | >>> | + | |
| - | ``` | + | |
| - | + | ||
| - | Les deux points ont les mêmes coordonnées mais ce sont néanmoins deux points différents. | + | |
| - | + | ||
| - | En écrivant `Point(2, | + | |
| - | + | ||
| - | + | ||
| - | ### Exercice 6 - problème de dépendance | + | |
| - | + | ||
| - | Supposons que l'on veuille ajouter une fonction qui détermine si un point est contenu dans un triangle. Selon vous, quel est le meilleur choix ? | + | |
| - | + | ||
| - | * dans la classe `Point`, définir la méthode `estDansTriangle(self, | + | |
| - | * dans la classe `Triangle`, | + | |
| - | * en dehors des deux classes, définir une fonction `triangleContientPoint(triangle, | + | |
| - | + | ||
| - | ### Dépendance | + | |
| - | Le diagramme UML permet de faire apparaître que la classe `Triangle` utilise la classe `Point`. | + | |
| - | </ | + | |
| - | + | ||
| - | {{ : | + | |
| - | + | ||
| - | < | + | |
| - | ### | + | |
| - | + | ||
| - | Quand on définit `x = 5` et `y = 12`, on peut faire avec `x` et `y` un certains nombres d' | + | |
| - | + | ||
| - | * On peut additionner `x + y` | + | |
| - | * On peut comparer `x <= y` | + | |
| - | * On peut afficher `print(x)`, ce qui provoque le **transtypage** de `x`, `int -> str` | + | |
| - | + | ||
| - | Si on souhaite pouvoir faire ce genre d' | + | |
| - | + | ||
| - | Le cas le plus courant est l' | + | |
| - | + | ||
| - | Il faut utiliser la méthode `__str__(self)` | + | |
| - | + | ||
| - | ```python | + | |
| - | # Dans la classe Point | + | |
| - | def __str__(self): | + | |
| - | """ | + | |
| - | transtypage -> str | + | |
| - | """ | + | |
| - | return "({} ; {})" | + | |
| - | ``` | + | |
| - | + | ||
| - | ### Exercice 7 | + | |
| - | + | ||
| - | Ajoutez une fonction de transtypage vers `str` dans la classe `Triangle`. | + | |
| - | + | ||
| - | Pensez à tester. | + | |
| - | + | ||
| - | ### Exercice 8 | + | |
| - | + | ||
| - | * Proposez une implémentation pour les **piles** en utilisant des classes. | + | |
| - | * Même chose pour les **files**. | + | |
| - | * Dans les deux cas, prévoyez une méthode `__str__` | + | |
| - | + | ||
| - | + | ||
| - | ### Exercice 9 ++ | + | |
| - | + | ||
| - | On peut aller plus loin en ajoutant des vecteurs, en définissant le produit scalaire... | + | |
| - | + | ||
| - | ### Exercice 10 ++ | + | |
| - | </ | + | |
| - | [[classe_relation_exercice|Implémentation d' | + | Supposons que l'on crée une classe '' |
| + | {{ nsi: | ||
nsi/terminales/classes.1624464009.txt.gz · Dernière modification : de goupillwiki
