Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Licence CC BY-NC-ND Thierry Parmentelat & Arnaud Legout Inria - UCA

Complément - niveau basique

Importations multiples - rechargement

Un module n’est chargé qu’une fois

De manière générale, à l’intérieur d’un interpréteur python, un module donné n’est chargé qu’une seule fois. L’idée est naturellement que si plusieurs modules différents importent le même module, (ou si un même module en importe un autre plusieurs fois) on ne paie le prix du chargement du module qu’une seule fois.

Voyons cela sur un exemple simpliste, importons un module pour la première fois :

import multiple_import
chargement de multiple_import

Ce module est très simple, comme vous pouvez le voir

from modtools import show_module
show_module(multiple_import)
Fichier /__w/course/course/modules/multiple_import.py
----------------------------------------
1|"""
2|Ce module est conçu pour illustrer le mécanisme de
3|chargement / rechargement
4|"""
5|
6|print("chargement de", __name__)

Si on le charge une deuxième fois (peu importe où, dans le même module, un autre module, une fonction..), vous remarquez qu’il ne produit aucune impression

import multiple_import

Ce qui confirme que le module a déjà été chargé, donc cette instruction import n’a aucun effet autre qu’affecter la variable multiple_import de nouveau à l’objet module déjà chargé. En résumé, l’instruction import fait l’opération d’affectation autant de fois qu’on appelle import, mais elle ne charge le module qu’une seule fois à la première importation.

Une autre façon d’illustrer ce trait est d’importer plusieurs fois le module this

# la première fois le chargement a vraiment lieu
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.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
# la deuxième fois il ne se passe plus rien
import this
The history saving thread hit an unexpected error (OperationalError('attempt to write a readonly database')).History will not be written to the database.

Les raisons de ce choix

Le choix de ne charger le module qu’une seule fois est motivé par plusieurs considérations.

def ma_fonction():
    import un_module_improbable
    ....

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

Les inconvénients de ce choix - la fonction reload

L’inconvénient majeur de cette stratégie de chargement unique est perceptible dans l’interpréteur interactif pendant le développement. Nous avons vu comment IDLE traite le problème en remettant l’interpréteur dans un état vierge lorsqu’on utilise la touche F5. Mais dans l’interpréteur “de base”, on n’a pas cette possibilité.

Pour cette raison, 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)
chargement de multiple_import
<module 'multiple_import' from '/__w/course/course/modules/multiple_import.py'>

Remarquez bien que importlib.reload est une fonction et non une instruction comme import - d’où la syntaxe avec les parenthèses qui n’est pas celle de import.

Notez également que la fonction importlib.reload a été introduite en python3.4, avant, il fallait utiliser la fonction imp.reload qui est dépréciée depuis python3.4 mais qui existe toujours. Évidemment, vous devez maintenant exlusivement utiliser la fonction importlib.reload.


NOTE spécifique à l’environnement des notebooks (en fait, à l’utilisation de ipython) :

À l’intérieur d’un notebook, vous pouvez faire comme ceci pour recharger le code importé automatiquement :

# charger le magic 'autoreload'
%load_ext autoreload
# activer autoreload
%autoreload 2

À partir de cet instant, et si le code d’un module importé est modifié par ailleurs (ce qui est difficile à simuler dans notre environnement), alors le module en question sera effectivement rechargé lors du prochain import. Voyez le lien ci-dessus pour plus de détails.

Complément - niveau avancé

Revenons à python standard. Pour ceux qui sont intéressés par les détails, signalons enfin les deux variables suivantes.

sys.modules

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

import sys
'csv' in sys.modules
True
import csv
'csv' in sys.modules
True
csv is sys.modules['csv']
True

La documentation sur sys.modules indique qu’il est possible de forcer le rechargement d’un module en l’enlevant de cette variable sys.modules.

del sys.modules['multiple_import']
import multiple_import
chargement de multiple_import

sys.builtin_module_names

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

Pour en savoir plus

Pour aller plus loin, vous pouvez lire la documentation sur l’instruction import