Outils pour utilisateurs

Outils du site


cours:informatique:fun_mooc:python3_uca_inria:560_importation_de_module

Python: mécanisme d'importation des modules

Nous abordons ici le processus d'importation des modules, c'est-à-dire les différentes étapes que va suivre l'interpréteur Python du moment où on tape l'instruction *import* jusqu'au moment où l'objet module est disponible.

Lorsque l'on importe un module, on utilise l'instruction import, par exemple:

# Importation du module os
>>> import os
 
# Après interprétation de cette instruction, une variable
# os est disponible elle référence un objet de type module
>>> print(os)
<module 'os' from '/usr/lib/python3.8/os.py'>

Le mot après l'instruction import, ici os a deux rôles:

  1. Il va définir le nom du fichier qui va être cherché sur le disque dur, qui va s'appeler os.py ( la plupart des modules sont écrits en python et ont une extension “.py” à quelques exceptions près directement écrits en *C*).
  2. os définit également le nom de la variable qui va référencer l'objet module.

Principales étapes de l'importation

Premièrement, il faut trouver le fichier sur le disque dur. Pour cela, Python va regarder dans un certain nombre de répertoires.

  • Le répertoire où se trouve le point d'entrée (le point d'entrée est le nom du fichier que vous passez à l'interpréteur lorsque vous démarrez votre programme).
  • En mode interactif, c'est le répertoire courant qui est scruté par défaut;

Ensuite, s'il ne trouve pas ce fichier, il va le chercher dans la variable système qui s'appelle `PYTHONPATH`.

Le module *os*, inclus un dictionnaire nommé *environ* (pour environnement), qui contient toutes les variables d'environnement du système sur lequel le programme s'exécute. On peut accéder à la valeur de cette variable `PYTHONPATH`:

>>> print(os.environ['PYTHONPATH'])

si le fichier n'est pas présent, au final, l’interpréteur va le chercher dans le répertoire des librairies standards. C'est pour ça qu'on peut importer n'importe quel module de la librairie standard sans avoir à se soucier de l'endroit où se situe ce fichier module.

Lorsque l'on a un doute sur le chemin de recherche, en fait, on peut regarder dans une variable qui s'appelle `sys.path`. Donc importons le module `sys` et `sys.path` est une liste qui contient tous les chemins qui sont suivis par l'interpréteur Python dans l'ordre, du premier chemin au dernier.

>>> import sys
 
>>> print(sys.path)
['/usr/bin', '/usr/lib/python38.zip', '/usr/lib/python3.8', '/usr/lib/python3.8/lib-dynload', '', '/usr/local/lib/python3.8/dist-packages', '/usr/lib/python3/dist-packages', '/usr/lib/python3/dist-packages/IPython/extensions', '/home/yoann/.ipython']

Cette variable étant une liste, on peut la modifier en cours d'exécution et lorsque l'on fera une importation, le processus d'importation regardera l'état actuel de cette variable.

C'est ce qui nous permet, dans un programme, de pouvoir adapter les chemins de recherche des modules.

A présent que le fichier source du module a été identifié, l'interpréteur va devoir le pré-compiler ; la pré-compilation consiste à générer ce qu'on appelle du *bytecode*. Ce *bytecode* est stocké dans des fichiers d' extension .pyc. Tous ces fichiers bytecode vont être mis dans un répertoire qui s'appelle pycache. Ce répertoire est en général là où vous exécutez votre programme.

Pour finir, l'interpréteur Python, une fois qu'il a généré le *bytecode*, va évaluer ce *bytecode* pour générer l'objet module. Je vous rappelle qu'un module s'importe toujours de manière séquentielle donc on va parcourir les lignes de la première ligne à la dernière ligne de code dans l'ordre, du début jusqu'à la fin, et que lorsque l'on rencontre une fonction, on va créer les objets fonction ; par contre, le bloc de code de la fonction ne sera évalué qu'à l'appel de la fonction.

Le processus d'importation étant une opération coûteuse, l'interpréteur, lorsque vous faites de multiples *import* vers le même module, ne va importer ce module qu'une seule fois, et il va ensuite créer des références partagées vers cet objet module. C'est pourquoi il est très important de comprendre qu'un objet module est mutable, et que la manière d'importer un module peut avoir un impact sur l'espace de nommage de ce module ou l'espace de nommage de votre programme.

import est une instruction comme une autre, et vous trouverez occasionnellement un avantage à l'utiliser à l'intérieur d'une fonction, sans aucun surcoût puisque vous ne payez le prix de l'import qu'au premier appel et non à chaque appel de la fonction.

>>> def ma_fonction():
...    import un_module_improbable
...    ....

Cet usage n'est pas recommandé en général, mais peut s'avérer très pratique pour alléger les dépendances entre modules dans des contextes particuliers, comme du code multi-plateformes.

Forcer la recharge d'un module

Cette stratégie de chargement unique des modules est appliquée par défaut mais python fournit dans le module importlib une fonction reload, qui permet comme son nom l'indique de forcer le rechargement d'un module, comme ceci:

>>> from importlib import reload
>>> reload(multiple_import)
importlib.reload est une fonction et non une instruction comme import: d'où cette syntaxe avec des parenthèses qui n'est pas celle de import.

Lister les modules chargés

L'interpréteur utilise la variable sys.modules pour conserver la trace des modules actuellement chargés.

# vérifie si un module est chargé
>>> 'this' in sys.modules
True
 
# les appels successif d'import ne produisent pas
# d'affichage car le module est déjà chargé
 
>>> import this
 
>>> import this
 
# On peut forcer un rechargement de module si on retire le module
# du dictionnaire sys.module
>>> del sys.modules['this']
 
# l'import suivant produit un affichage, le module est bien rechargé
>>> import this
The Zen of Python, by Tim Peters
 
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
...

Signalons enfin la variable sys.builtin_module_names qui contient le nom des modules, comme par exemple le garbage collector gc, qui sont implémentés en C et font partie intégrante de l'interpréteur.

>>> 'gc' in sys.builtin_module_names
True
cours/informatique/fun_mooc/python3_uca_inria/560_importation_de_module.txt · Dernière modification : 2021/05/19 19:22 de yoann