## Modularité

### Le programme

![bo.png](assets/bo.png)

> 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>.

