Modularité

Numérique et Sciences Informatiques

donnees

Lorsqu’on développe un logiciel à grande échelle, une des clés consiste à bien séparer les différentes parties du programme. On cherche aussi à utiliser des structures déjà existantes.
Pour cela on utilise des fichiers appelés modules.

En python, il existe une bibliothèque (Une bibliothèque est constituée de plusieurs modules) native qui contient de nombreux outils . Il existe de nombreuses bibliothèques disponibles en langage python. On connaît déjà des modules préexistants en Python (math, random, tkinter, etc.). Ici, on détaille comment créer et utiliser ses propres modules.

Modules, interface et réalisation

Un modules est un fichier contenant un ensemble de fonctions outils pouvant être utilisées dans un autre logiciel.
Pour créer un module en Python, il suffit de regrouper ces fonctions dans un unique fichier : mon_module.py
Pour importer un module personnel dans un programme, on procède comme avec les modules préexistant en Python :

import mon_module

Pour chaque module on distingue :

  • son implémentation, c’est à dire le code lui même ;
  • son interface, consistant en la liste des fonctions utilisables du module, assorties d’une description de celles-ci. Une interface est un moyen pour un utilisateur du module de pouvoir prendre en main celui-ci sans connaître le détail de la réalisation.
    Il faut être clair dans la description des fonctions et préciser :
    • l’effet des différentes fonctions ;
    • les arguments principaux et optionnels ;
    • leurs types et éventuellement les valeurs interdites.

Encapsulation

L'auteur d'un module peut travailler indépendamment avec ses propres solutions, mais sa solution doit donner les résultats annoncés par le contrat interface.

L'auteur d'un module peut donc programmer ses propres fonctions à usage interne, ou privé.
On parle d'encapsulation. Celles-ci ne doivent pas être utilisées directement par les modules clients (le programme principal, par exemple).
Dans les modules, on les signale avec le symbole _ (2 underscores) devant la fonction : _nom_de_la_fonction.

Les mises à jour (modifications, améliorations…) des modules doivent rester compatibles avec l'interface.

Par convention la fonction précédée de 2 underscores est privée _fonction(…) alors que fonction( …) appartient à l'interface

Exceptions

Un utilisateur n'a pas besoin de comprendre comment fonctionne un module, il faut donc prévenir les erreurs d'exécution.

Lorsque l’on veut signaler des erreurs à un utilisateur, on utilise les exceptions.
Une exception interrompt le programme. Les modules doivent donc gérer correctement les exceptions.
Il existe plusieurs type d’exceptions :

NameError accès à une variable inexistante
IndexError accès à un indice non valide
IndexError accès à une clé de dictionnaire non valide
ZeroDivisionError division par zéro
TypeError opération appliqué à des valeurs incompatibles

Lever une exception : Il est possible de déclencher manuellement n’importe quelle exception via la commande raise : raise nom_exception(texte à afficher)

Rattraper une exception : Pour ne pas interrompre l’exécution du programme en cas d’erreur, il est possible de rattraper une exception à l’aide de la syntaxe try / except :

try :
	except exception 1:
		bloc alternatif 1
	except exception 2:
		bloc alternatif 2

Documenter un module

En programmation, spécifier un programme revient à décrire explicitement ce qu’il doit faire et dans quelles conditions.

Intérêt:

  • programmer : documenter AVANT d’écrire le code donne un objectif clair
  • relire : les programmes complexes sont difficiles à comprendre. La documentation simplifie cette étape
  • collaborer : travailler à plusieurs demande de l’organisation et une documentation claire est indispensable

Les docstrings sont des chaînes de commentaires qui doivent être placées juste en dessous des définitions de fonction ou de classe, ou bien tout en haut d'un module. L'intérêt, c'est que les docstrings sont récupérables dynamiquement via l'attribut __doc__, ou grâce à la fonction primitive Help(ma_fonction). Cela permet notamment de faire de la documentation pour aider vos utilisateurs et vous-même avec la documentation de votre projet.

""" Module test
Ce module présente deux fonctions:
- addition : renvoie la somme de a et b
- multiplication : renvoi le produit de a et b
"""

def addition(a, b):
  """
  Cette fonction est une fonction de test
  Elle sert a calculer a + b
  :param a : Valeur 1
  :param b : Valeur 2
  :return : Somme des Valeur 1 et Valeur 2
  :CU : a et b entiers.
  3
  """
  return a + b

def multiplication(a, b):
  """
  Cette fonction est une fonction de test
  Elle sert a calculer a * b
  
  :param a : Valeur 1
  :param b : Valeur 2
  :return : produit des Valeur 1 et Valeur 2
  :CU : a et b entiers.
  >>> ma_fonction(1,2)
  2
  """
  return a * b

On fournit une fonction en ne donnant que sa déclaration (et ses paramètres) et en spécifiant dans la documentation :

  • Ce qui fait la fonction de manière succinte
  • Les paramètres d’entrées et leur type :
    :param n (int): indice
    @param n: (int) indice
  • La sortie et son type :
    :return(float): moyenne
    @return: (float) moyenne
    Pas de sortie ? :return: (None)  ou   @return: (None)
  • Les conditions d’utilisation et effets de bord :  :CU : a entier positif   ou  @CU : a entier positif
  • Eventuellement des tests

Entraînement 1 :

A vous de vous documenter !
Vous devez utiliser la documentation de turtle et réalisez un un dessin avec :

  • au moins trois figures géométrique différentes
  • au moins trois couleurs différentes

Exemple : Notre module

Nous allons imaginer le module convertir qui comme son nom l'indique permet de convertir des kilomètres en miles et inversement.

""" Module convertir une distance

Pour rappel, on emploie dans le système impérial le mille terrestre
d'une longueur d'environ 1 609 mètres

Ce module présente deux fonctions:

- km: renvoie une distance en miles en km
- miles: renvoie une distance en km en miles

"""
        
def km(data):
    """
    Elle sert a convertir des kilomètres en miles

    :param (float): data
    :return (float): 
    :CU : data > 0
    >>> km(1)
    0.62137
    """
    return float(data) / 1.609

def miles(data):
    """
    Elle sert a convertir des miles en kilomètres 

    :param (float): data
    :return (float): 
    :CU : data > 0
    >>> km(1)
    0.62137
    """
    return float(data) * 1.609

API (Application Programming Interface)

En informatique, une interface de programmation d’application (désignée par le terme API pour Application Programming Interface) permet de rendre disponibles les données ou les fonctionnalités d’une application existante afin que d’autres applications les utilisent. Utiliser une API permet donc d’utiliser un programme existant plutôt que de le re-développer.

Cela peut permettre par exemple de récupérer des données structurées depuis un site web pour les exploiter de manière automatisée dans un programme.

Entraînement :

Nous allons imaginer le module decallage_horraire qui permet de calculer l'heure à Paris quand nous sommes en voyage à Pékin, Gosier, Rio, Tokyo, Sydney.

  1. Implémenter et documenter le module decallage_horraire
  2. Ajouter une fonction qui permet de transformer l'horraire entre 2 villes.
    dh.convertir(Gosier,14h00)
    >>> il est 19h à Paris.
  3. Vérifier son bon fonctionnement

Savoir faire

  • Utiliser des API (Application Programming Interface) ou des bibliothèques.
  • Créer des modules simples et les documenter.

Fiche de cours