Les modules¶
Un programme Python est écrit dans un fichier portant l’extension .py. Cependant, pour la plupart des programmes, le recours à un seul fichier n’est pas très pratique car le nombre de lignes de code augmente très rapidement au fur et à mesure de l’ajout de fonctionnalités dans l’application.
Les modules permettent de découper logiquement le code source de l’application à travers plusieurs fichiers. Un module peut même être partagé entre plusieurs applications afin de créer une bibliothèque logiciel réutilisable. Par exemple, Python fournit déjà une bibliothèque standard utilisable par toutes les applications sous la forme de plusieurs modules.
Le module pour prévenir la collision de nom¶
Un problème récurrent en programmation est celui de la collision de noms. Écrire un programme implique de nommer les différents éléments du programme (variables, paramètres, fonctions, objets…). Si on désire réutiliser des fonctions développées par d’autres personnes, il est possible que l’on soit amené à incorporer des fonctions qui portent le même nom. En Python, si on déclare une fonction avec un nom déjà utilisé pour désigner une autre fonction, cette dernière ne sera plus accessible. On se retrouve confronté à un phénomène de collision des noms.
Pour résoudre cette situation, la solution la plus couramment utilisée consiste à
créer des espaces de noms différents pour les deux fonctions. En Python, un module
porte un nom qui identifie un espace dans lequel on peut définir des fonctions.
Ainsi si les modules module1
et le module2
définissent tous les deux une
fonction s’appelant abs()
, il sera possible de les distinguer à l’appel
en préfixant le nom de la fonction par le nom du module :
module1.abs()
module2.abs()
abs(2)
Dans l’exemple ci-dessus, il est même possible d’appeler la méthode standard
abs()
qui permet de calculer la valeur absolue d’un nombre.
La bibliothèque standard Python¶
La bibliothèque standard Python contient déjà beaucoup de modules. La liste ci-dessous énumère les modules les plus utiles à connaître pour débuter en Python :
variables et fonctions pour interagir avec l’interpréteur Python |
|
fonctions élémentaires pour interagir avec le système d’exploitation |
|
fonctions mathématiques avancées |
|
bibliothèque pour la génération de nombres aléatoires |
|
représentation des dates et du temps |
|
gestion du calendrier |
|
structures de données supplémentaires pour les séquences et les dictionnaires |
Importer un module¶
Pour accéder à un élément d’un module, il faut d’abord importer le module grâce
au mot-clé import
. Par exemple, le module sys
définit la variable
version
qui contient la version de l’interpréteur Python. Pour
pouvoir y accéder, il faut préalablement importer le module sys
:
import sys
print(sys.version)
De même, le module random
définit la fonction random()
qui
retourne un nombre compris entre 0 et 1 :
import random
nombre = random.random()
print(nombre)
L’instruction import
peut être placée à n’importe quel endroit dans un programme
(y compris dans le corps d’une fonction). Cela permet d’importer le module uniquement
lorsqu’il est réellement nécessaire d’accéder à un élément qu’il définit.
Note
Si vous souhaitez importer plusieurs modules, vous pouvez utiliser une seule
instruction import
en séparant le nom des modules par une virgule :
import os, sys, random
Il est possible de donner un alias au moment de l’import pour référencer le module sous un autre nom.
import random as r
nombre = r.random()
print(nombre)
Importer directement un nom¶
Parfois, vous ne souhaitez pas importer tout un module et il peut être fastidieux
de préfixer systématiquement un nom par le module qui le définit. Il existe
la syntaxe from ... import
pour résoudre cette situation :
from sys import version
print(version)
Grâce à cette syntaxe, la variable version
du module sys
est directement accessible par son nom.
Cette syntaxe est également utilisable pour les fonctions :
from math import factorial
f = factorial(5)
print(f)
# Affiche 120
Note
Si vous souhaitez importer plusieurs noms du même module, vous pouvez utiliser
une seule instruction from ... import
en séparant les noms par une virgule :
from sys import version, platform, exit
Il est possible de donner un alias au moment de l’import pour référencer l’élément importé.
from math import factorial as f
resultat = f(3)
print(resultat)
# Affiche 6
Note
Vous pouvez importer tous les noms définis dans un module en utilisant *
:
from math import *
v = factorial(5)
f = floor(10.25)
l = log(2)
print(v, f, l)
# Affiche 120 10 0.6931471805599453
Cette syntaxe n’est pas conseillée car il est difficile de connaître avec certitude la liste des noms importés.
Créer un module à partir d’un fichier¶
Tout fichier source Python (fichier avec l’extension .py) peut être utilisé comme un module. Il est donc très simple de concevoir une application Python composée de plusieurs fichiers : un fichier sert de fichier principal pour le lancement de l’application tandis que les autres fichiers sont utilisés comme des modules.
Supposons qu’une application python est composée de deux fichiers : app.py
qui contient le programme principal et entree_sortie.py
qui regroupe
les fonctions pour interagir avec l’utilisateur.
entree_sortie.py
¶1 2 3 4 5 6 | def demander_nom():
nom = input("Comment vous appelez-vous ? ")
return nom
def afficher(*args):
print(*args)
|
app.py
¶1 2 3 4 | from entree_sortie import demander_nom, afficher
nom = demander_nom()
afficher("Bonjour", nom)
|
Le nom du module correspond au nom du fichier. Le programme principal dans
le fichier app.py
peut importer et utiliser les fonctions définies
dans le module entree_sortie
, c’est-à-dire dans le fichier entree_sortie.py
.
Module exécutable¶
Si un module déclare directement du code en dehors de toute fonction,
ce code sera exécuté lors du premier import du module. Si vous
le souhaitez, un module peut avoir une comportement différent s’il est exécuté
directement par l’interpréteur (comme programme principal) ou s’il est importé
depuis un autre fichier. Cela permet de créer des modules exécutables de
manière autonome. Pour cela, il suffit de tester la valeur de l’attribut
du module appelé __name__
. Si cet attribut vaut "__main__"
alors
cela signifie que le fichier est lancée directement par l’interpréteur. Il
n’est pas importé et n’agit donc pas comme un module.
if __name__ == "__main__":
# Il est possible d'exécuter du code pour un module qui est
# directement appelé depuis l'interpréteur Python
pass
Créer un module à partir d’un répertoire¶
Parfois un module est tellement complexe qu’il peut être organisé dans plusieurs
fichiers, chacun agissant comme un sous-module du module principal. Dans ce cas,
il faut placer tous les fichiers du module dans un répertoire portant le nom
du module. Ce répertoire doit contenir un fichier nommé __init__.py
qui représente le point d’entrée du module.
Si nous reprenons notre exemple précédent, nous pouvons créer le module
entree_sortie
en créant un répertoire du même nom avec, par exemple, les
fichiers suivants à l’intérieur :
entree_sortie/entree.py
¶1 2 3 | def demander_nom():
nom = input("Comment vous appelez-vous ? ")
return nom
|
entree_sortie/sortie.py
¶1 2 | def afficher(*args):
print(*args)
|
entree_sortie/__init__.py
¶1 2 | from entree_sortie.entree import demander_nom
from entree_sortie.sortie import afficher
|
Le module entree_sortie
est maintenant représenté par une répertoire qui
contient plusieurs fichiers. Le fichier __init__.py
se limite à importer
les fonctions demander_nom()
et afficher()
dans son propre espace de noms
qui est celui du module entree_sortie
. Le programme principal n’a pas a être
modifié par rapport à l’exemple de la section précédente :
app.py
¶1 2 3 4 | from entree_sortie import demander_nom, afficher
nom = demander_nom()
afficher("Bonjour", nom)
|
Module répertoire exécutable¶
Si un module est représenté par un répertoire, il est possible de le rendre
exécutable en ajoutant un fichier __main__.py
dans le répertoire. Ce
fichier contient le code a exécuter uniquement si le module est lancé directement
à partir de l’interpréteur Python grâce à l’option -m
:
python3 -m mon_module
Chemin des modules¶
Comme un module est représenté par un fichier ou par un répertoire, l’interpréteur
doit définir quel est l’emplacement par défaut des modules. L’ensemble des
répertoires pouvant contenir des modules est appelé le path. Il est accessible
directement par un programme avec sys.path
.
import sys
print(sys.path)
# Affiche sur un système Linux
# ['', '/usr/lib/python36.zip', '/usr/lib/python3.6',
# '/usr/lib/python3.6/lib-dynload', '/usr/local/lib/python3.6/dist-packages',
# '/usr/lib/python3/dist-packages', '/usr/lib/python3.6/dist-packages']
Pour un système Linux, la variable sys.path
indique tous les répertoires
systèmes pouvant contenir des modules Python sous la forme d’un tableau. Le
premier chemin indiqué est ''
, ce qui signifie que l’interpréteur cherche
en priorité un module directement à partir du répertoire de travail dans lequel
l’interpréteur a été lancé.
Il est possible de modifier le contenu de sys.path
par programmation. On
peut également utiliser la variable d’environnement système PYTHONPATH
pour
ajouter des chemins supplémentaires au moment du lancement de l’interpréteur.
Si on souhaite spécifier plusieurs chemins, il faut les séparer par :
.
$ export PYTHONPATH="/monrepertoire/python:/monrepertoire2"
$ python3
import sys
print(sys.path)
# Affiche sur un système Linux
# ['', '/monrepertoire/python', '/monrepertoire2', '/usr/lib/python36.zip',
# '/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload',
# '/usr/local/lib/python3.6/dist-packages', '/usr/lib/python3/dist-packages',
# '/usr/lib/python3.6/dist-packages']
Les packages¶
Les packages en Python désignent le fait de pouvoir structurer l’organisation des fichiers d’un projet dans une arborescence de répertoires. Par exemple si un projet a l’arborescence suivante :
stock/
__init__.py
ecran/
__init__.py
accueil.py
detail_produit.py
gestion
__init__.py
produit.py
commande.py
Il est possible d’importer le module commande
en utilisant son chemin de packages :
import stock.gestion.commande
stock.gestion.commande.traiter_commande()
Si on veut éviter de préciser systématiquement le chemin de packages pour accéder
à élément du module, on peut utiliser la syntaxe du from ... import
:
from stock.gestion import commande
commande.traiter_commande()
Note
La présence des fichiers __init__.py
est obligatoire dans l’arborescence
des packages pour que l’interpréteur Python traite chaque répertoire comme
un module. Ces fichiers peuvent être vides.
Lorsque vous importez un module dans un chemin de package, le fichier
__init__.py
de chaque répertoire est appelé pour initialiser chacun
des modules. Un module n’est initialisé qu’une fois ! Les imports successifs
de ce module ou d’un sous module n’exécuteront plus son fichier __init__.py
.
Import relatif¶
Dans une arborescence de packages, il est parfois plus simple d’utiliser un import
relatif. Dans l’exemple d’arborescence précédent, supposons que dans le module
stock.gestion.produit
, on souhaite importer des fonctions présentes dans le
fichier produit.py
, on peut écrire :
commande.py
¶import stock.gestion.produit
Cela a comme inconvénient de rendre le contenu du fichier dépendant
de l’arborescence des packages. On peut également recourir à un import
relatif. Puisque les fichiers commande.py
et produit.py
sont
dans le même répertoire, on peut écrire :
commande.py
¶from . import produit
On peut également remonter dans l’arborescence en utilisant ..
:
commande.py
¶from ..ecran import accueil
Exercices¶
Exercice en forme d’astuce
Essayez la commande :
python -m http.server
Exercice : Trouver un nombre
Utilisez la fonction randint()
du module random
pour
tirer un nombre aléatoirement entre 1 et 20.
L’utilisateur a droit à trois tentatives pour deviner ce nombre.
Exercice : Afficher la date
Utilisez la fonction datetime.now()
du module datetime
pour connaître la date et l’heure et l’afficher.
Exercice : Organiser un projet en module
Reprenez le projet pour l’affichage de l’écart avec la taille. Découpez
ce projet avec un module sous la forme d’un répertoire qui s’appelle taille
.
Le contenu du module doit être :
taille
__init__.py
__main__.py
entree_sortie.py
calcul.py
Le module entree_sortie
doit regrouper les fonctions pour interagir avec
l’utilisateur. Le module calcul
doit regrouper la fonction de calcul
de différence. Le fichier principal du module __main__
doit permettre
d’exécuter le programme.
L’application peut maintenant s’exécuter directement en ligne de commande en invoquant le module :
$ python -m taille