Comme l'a fait remarquer @L3viathan, c'est facile à partir de Python 3.7 : il suffit de définir un __getattr__
dans votre module spécial. Ainsi, par exemple, vous pouvez créer un module "echo" (qui renvoie simplement le nom de l'objet demandé) comme ceci :
echo.py
(Python >=3.7)
def __getattr__(name):
return name
Alors vous pourriez l'utiliser comme ceci :
from echo import x
print(repr(x))
# 'x'
Sur les versions antérieures de Python, vous devez sous-classer le module, comme le suggère la rubrique PEP-562 . Cela fonctionne également dans Python 3.7.
echo.py
(Python >=2)
import sys, types
class EchoModule(types.ModuleType):
def __getattr__(self, name):
return name
sys.modules[__name__] = EchoModule(__name__)
Vous l'utiliserez de la même manière que la version 3.7 : from echo import something
.
Mise à jour
Pour une raison quelconque, Python tente de récupérer l'attribut deux fois pour chaque from echo import <x>
appel. Il appelle également __getattr__('__path__')
lorsque le module est chargé. Vous pouvez éviter les effets secondaires dans ces cas avec le code suivant :
echo.py
(ne définir les attributs qu'une seule fois)
import sys, types
class EchoModule(types.ModuleType):
def __getattr__(self, name):
# don't define __path__ attribute
if name == '__path__':
raise AttributeError
print("importing {}".format(name))
# create the attribute in case it's required again
setattr(self, name, name)
# return the new attribute
return getattr(self, name)
sys.modules[__name__] = EchoModule(__name__)
Ce code crée un attribut dans le fichier echo
à chaque fois qu'un attribut précédemment inutilisé est importé (un peu comme le module collections.defaultdict
). Ensuite, si Python tente d'importer à nouveau ce même attribut par la suite, il le tirera directement du module au lieu de faire appel à __getattr__
(c'est comportement normal pour les attributs des objets).
Il y a aussi un peu de code ici pour éviter de mettre en place un mauvais __path__
ce qui permet également d'éviter d'exécuter votre code lorsque l'attribut __path__
est demandé. Notez que c'est peut-être la partie la plus importante ; lorsque j'ai testé, le simple fait d'élever la valeur de AttributeError
para __path__
était suffisant pour empêcher le double accès à l'attribut nommé.