196 lines
6.8 KiB
Markdown
196 lines
6.8 KiB
Markdown
## Modularité
|
||
|
||
### Le programme
|
||
|
||

|
||
|
||
> Comme vu lors de l'année de première, Python offre une multitude de modules, qui permettent d'utiliser de nombreuses fonctionnalités, d'adapter son programme à un usage précis, mais également de participer aux efforts de la communauté du logiciel libre.
|
||
|
||
|
||
|
||
### Principe
|
||
|
||
La modularité est un concept permettant la réutilisation de code au travers des fonctions, facilitant la maintenance, les tests, et donc, un gain de temps, ainsi que de visibilité. Pensez à la construction d’une maison : chaque pièce (module) a une fonction spécifique et peut être construite indépendamment des autres.
|
||
|
||
En informatique, les projets peuvent être maintenus par plusieurs personnes et il n'est pas rare qu'un fichier soit modifié par plusieurs personnes.
|
||
|
||
C'est pourquoi il est important, lorsque l'on développe, d'être clair et précis tant dans la structuration du programme que dans la documentation.
|
||
|
||
Il faudra donc prendre de bonnes habitudes :
|
||
|
||
- découper son code en fonctions
|
||
- grouper les fonctions par fichier
|
||
- regrouper les fonctions dans des classes (que nous verrons plus tard)
|
||
|
||
Interessons nous au code python ci dessous. Ici, la structure compte plus que le code en lui même.
|
||
|
||
```python
|
||
## importations
|
||
from math import *
|
||
import doctest
|
||
|
||
## variables
|
||
VALEUR = 25
|
||
|
||
## fonctions
|
||
def racine(val):
|
||
"""
|
||
Renvoie la racine carré d'un nombre.
|
||
|
||
:param val: (int) un entier
|
||
:return: (float) la racine carré
|
||
:CU: type(val) == int && val >= 0
|
||
|
||
example:
|
||
>>> racine(VALEUR)
|
||
5.0
|
||
"""
|
||
return sqrt(val)
|
||
|
||
## programme
|
||
print(racine(VALEUR))
|
||
|
||
if __name__=="__main__":
|
||
doctest.testmod(verbose=True)
|
||
```
|
||
|
||
Chaque bloc est caractérisé par un titre mis en commentaire par ces deux symboles dieses : *##*.
|
||
|
||
Avec une nomenclature sous cette forme, on gagne en visibilité et rendra les recherches d'un élément particulier plus rapides.
|
||
|
||
-------
|
||
|
||
### Programmation modulaire en python
|
||
|
||
Python est un langage qui autorise le regroupement de fonctions dans un groupe appelé **classe**.
|
||
|
||
- Ces fonctions sont alors appelées **méthodes**.
|
||
- On parle alors de **programmation orientée objet**. Nous verrons cela prochainement.
|
||
|
||
Pour gagner en visibilité dans un programme, la nomenclature ne suffit pas à elle seule. Une autre manière de gagner du temps consiste à écrire des ***modules*** qui ont une tache spécifique.
|
||
|
||
Lorsque l'on programme sous python, nous éditons des fichiers sous un format *.py*. Chacun de ces fichiers python est appelé **module**.
|
||
|
||
- Ces modules peuvent être alors regroupés dans un **package**.
|
||
|
||
Intéressons nous au programme vu précédemment :
|
||
|
||
```python
|
||
## importations
|
||
from math import *
|
||
import doctest
|
||
```
|
||
|
||
Au début du programme, nous avons une partie *import* où l'on ajoute toute les lignes d'importations. Ces dernières permettent de préciser à python que l'on ajoute à notre programme des élément du module **math** ainsi que du module **doctest**.
|
||
|
||
Chacun de ces modules a ses propres variables, fonctions et autre éléments. Le module math va donc réaliser des opérations mathématiques comme calculer la racine carrée avec la fonction **sqrt** et le module doctest va s'occuper de réaliser des tests unitaires.
|
||
|
||
Dans un TP/Projet, il va être important de faire plusieurs modules, ceci aura plusieurs avantages :
|
||
|
||
- des fichiers courts
|
||
- répartition du travail facilitée
|
||
- plus de visibilité lors d'une recherche d'un bug / d'une erreur
|
||
|
||
<u>***Attention***</u>
|
||
|
||
Utiliser **from xxx import *** peut sembler plus simple mais cela vous oblige donc à importer des modules inutiles ou non désirés dans votre code.
|
||
Prenez l'habitude de n'importer que les modules utiles pour votre programme.
|
||
|
||
--------
|
||
|
||
### Documentation
|
||
|
||
Un dernier point très important, c'est la documentation avec ses jeux de tests.
|
||
|
||
#### Docstring
|
||
|
||
Lorsque l'on utilise un module connu comme **math**, **random** ou encore **tkinter**, il est possible de trouver sa documentation en ligne afin de trouver les informations nous permettant de s'en servir correctement.
|
||
|
||
Il existe aussi une documentation que l'on peut récupérer via les modules grace à la fonction *help* :
|
||
|
||
```python
|
||
import random
|
||
|
||
help(random)
|
||
```
|
||
|
||
La documentation dans le module ne sert pas de décoration mais permet à celui ou celle (voir vous même ! ) comprendre les spécifications.
|
||
|
||
Voyons un exemple de **docstring** d'une fonction :
|
||
|
||
```python
|
||
def somme(n):
|
||
"""
|
||
Renvoie la somme des nombres entre 0 à n
|
||
|
||
:param n: (int) un nombre entier positif
|
||
:return: (int) la somme de 0 à n
|
||
:CU:
|
||
type(n) == int
|
||
n >= 0
|
||
"""
|
||
return sum([i for i in range(n+1)])
|
||
```
|
||
|
||
La documentation se trouve toujours au début de la fonction, avant la première ligne de son bloc d'instructions et on y retrouve plusieurs informations :
|
||
|
||
- Une phrase qui explique son comportement
|
||
- la liste des paramètres avec leur type
|
||
- le detail de ce qui est renvoyé avec son type
|
||
- les contraintes d'utilisation.
|
||
|
||
#### Doctest
|
||
|
||
Une bonne documentation comporte 2 parties :
|
||
|
||
- la première vu précédemment avec la docstring
|
||
- la deuxième avec la doctest
|
||
|
||
La doctest consiste à demander à votre interface de programmation python de réaliser des tests afin de vérifier si votre code fonctionne.
|
||
|
||
Pour réaliser ces tests unitaires, nous allons avoir besoin du module **doctest**.
|
||
|
||
Reprenons notre exemple et ajoutons y notre test :
|
||
|
||
```python
|
||
import doctest
|
||
|
||
def somme(n):
|
||
"""
|
||
Renvoie la somme des nombres entre 0 à n
|
||
|
||
:param n: (int) un nombre entier positif
|
||
:return: (int) la somme de 0 à n
|
||
:CU:
|
||
type(n) == int
|
||
n >= 0
|
||
|
||
Exemple:
|
||
>>> somme(5)
|
||
15
|
||
>>> somme(-1)
|
||
AssertionError: erreur
|
||
"""
|
||
assert type(n)==int, "erreur"
|
||
assert n >= 0, "erreur"
|
||
return sum([i for i in range(n+1)])
|
||
|
||
if __name__=="__main__":
|
||
doctest.testmod(verbose=True)
|
||
```
|
||
|
||
Lors de l'exécution du programme principal, la fonction *testmod* du module **doctest** va parcourir toute les documentations à la recherche de ligne commencant par ```>>>```.
|
||
|
||
Une fois les lignes trouvées, testmod va exécuter la ligne en question puis va comparer son résultat avec ce qui a été mis en dessous.
|
||
|
||
L'attribut *verbose* de la fonction testmod nous permet de dire à ce dernier de nous parler et de donner le détail des test, par défaut l'attribut est mis à False.
|
||
|
||
----------
|
||
|
||
Auteurs : Florian Mathieu, Enzo Frémeaux, Thimothée Decooster
|
||
|
||
Licence CC BY NC
|
||
|
||
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Licence Creative Commons Attribution - Pas d’Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International</a>.
|
||
|