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:47] – 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 45: | 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: |
| </ | </ | ||
| Ligne 85: | Ligne 87: | ||
| ==== Diagramme UML ==== | ==== Diagramme UML ==== | ||
| - | {{: | + | {{nsi: |
| Pour aider au développement et au travail de groupe, les informaticiens ont recours à différents types de diagrammes dont le but est de communiquer rapidement les choix effectués. Le UML -- Unified Modeling Language -- en fait partie. | Pour aider au développement et au travail de groupe, les informaticiens ont recours à différents types de diagrammes dont le but est de communiquer rapidement les choix effectués. Le UML -- Unified Modeling Language -- en fait partie. | ||
| Ligne 114: | Ligne 116: | ||
| Dans un programme complexe, le diagramme UML permettra d' | Dans un programme complexe, le diagramme UML permettra d' | ||
| - | ===== Implémentation Python ===== | + | ==== Dépendance ==== |
| - | + | ||
| - | ==== Syntaxe ==== | + | |
| - | + | ||
| - | <code python linenums> | + | |
| - | class NomDeLaClasse: | + | |
| - | """ | + | |
| - | commentaires décrivant à quoi sert la classe | + | |
| - | """ | + | |
| - | x: | + | |
| - | n:int = 0 # autre exemple, initialisé à 0 | + | |
| - | + | ||
| - | def __init__(self, | + | |
| - | """ | + | |
| - | méthode spéciale utilisée lors de la création d'un objet | + | |
| - | pour initialiser cet objet | + | |
| - | """ | + | |
| - | + | ||
| - | def une_fonction(self, | + | |
| - | """ | + | |
| - | Notez l' | + | |
| - | """ | + | |
| - | self.x # " | + | |
| - | + | ||
| - | c = NomDeLaClasse(14) # création d'un objet respectant le modèle définit par la classe | + | |
| - | c.x # désigne l' | + | |
| - | </ | + | |
| - | + | ||
| - | ==== Instanciation ==== | + | |
| - | + | ||
| - | Une classe définit un modèle. Quand on utilise ce modèle pour réaliser un objet concret, on parle d' | + | |
| - | + | ||
| - | Par exemple, nous sommes des instances du concept abstrait " | + | |
| - | + | ||
| - | ==== self ==== | + | |
| - | + | ||
| - | La classe définit le comportement d'un objet. Quand on a besoin de désigner l' | + | |
| - | + | ||
| - | Toutes les méthodes ordinaires d'une classe Python ont comme premier argument '' | + | |
| - | + | ||
| - | > Il existe des méthodes spéciales qui fonctionnent autrement. | + | |
| - | + | ||
| - | + | ||
| - | + | ||
| - | + | ||
| - | <file python triangle.py> | + | |
| - | class Triangle: # on utilise PascalCase = UpperCamelCase | + | |
| - | """ | + | |
| - | 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 = x1 # x1 est la valeur fournie | + | |
| - | # self.x1 est l' | + | |
| - | self.y1 = 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 = Triangle(0, | + | |
| - | 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`. | + | |
| - | + | ||
| - | + | ||
| - | + | ||
| - | + | ||
| - | ### 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 ++ | + | |
| - | </ | + | |
| + | Supposons que l'on crée une classe '' | ||
| + | {{ nsi: | ||
nsi/terminales/classes.1624466853.txt.gz · Dernière modification : de goupillwiki
