190 lines
6.8 KiB
Markdown
190 lines
6.8 KiB
Markdown
|
|
## Modularité
|
|||
|
|
|
|||
|
|
> 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.
|
|||
|
|
|
|||
|
|
----------
|
|||
|
|
|
|||
|
|
Auteur : Florian Mathieu
|
|||
|
|
|
|||
|
|
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>.
|
|||
|
|
|