J'écris une application Python qui prend comme commande un argument, par exemple:
$ python myapp.py command1
Je veux que l'application soit extensible, c'est-à-dire qu'elle puisse ajouter de nouveaux modules qui implémentent de nouvelles commandes sans avoir à changer la source principale de l'application. L'arbre ressemble à quelque chose comme:
myapp/
__init__.py
commands/
__init__.py
command1.py
command2.py
foo.py
bar.py
Je souhaite donc que l'application trouve les modules de commande disponibles au moment de l'exécution et exécute le module approprié.
Python définit une fonction __import__ , qui prend une chaîne pour un nom de module:
__import __ (nom, globaux = Aucun, locaux = Aucun, fromlist = (), niveau = 0)
La fonction importe le nom du module, en utilisant potentiellement les valeurs globales et locales données pour déterminer comment interpréter le nom dans un contexte de package. La fromlist donne les noms des objets ou sous-modules qui doivent être importés du module donné par nom.
Source: https://docs.python.org/3/library/functions.html# import
Donc, actuellement, j'ai quelque chose comme:
command = sys.argv[1]
try:
command_module = __import__("myapp.commands.%s" % command, fromlist=["myapp.commands"])
except ImportError:
# Display error message
command_module.run()
Cela fonctionne très bien, je me demande simplement s'il existe un moyen plus idiomatique d'accomplir ce que nous faisons avec ce code.
Notez que je ne veux pas spécifiquement utiliser des œufs ou des points d'extension. Ce n'est pas un projet open-source et je ne m'attends pas à ce qu'il y ait des "plugins". Le but est de simplifier le code de l'application principale et de supprimer la nécessité de le modifier chaque fois qu'un nouveau module de commande est ajouté.
la source
dir(__import__)
. La fromlist doit être une liste de noms à émuler "from import name ...".importlib
: stackoverflow.com/a/54956419/687896Réponses:
Avec Python plus ancien que 2.7 / 3.1, c'est à peu près ainsi que vous le faites.
Pour les versions plus récentes, voir
importlib.import_module
pour Python 2 et et Python 3 .Vous pouvez également l'utiliser
exec
si vous le souhaitez.Ou en utilisant,
__import__
vous pouvez importer une liste de modules en procédant comme suit:Extrait directement de Dive Into Python .
la source
__init__
ce module?__import__
. Les documents 2.7: "Parce que cette fonction est destinée à être utilisée par l'interpréteur Python et non à un usage général, il est préférable d'utiliser importlib.import_module () ..." Lors de l'utilisation de python3, leimp
module résout ce problème, comme le mentionne Monkut ci-dessous.foreach
quand vous en avezfor element in
etmap()
bien :)La méthode recommandée pour Python 2.7 et 3.1 et versions ultérieures consiste à utiliser le
importlib
module:par exemple
la source
__import__
fonction en faveur du module mentionné ci - dessus.os.path
; que diriez-vousfrom os.path import *
?globals().update(my_module.__dict)
Comme mentionné, le module imp vous offre des fonctions de chargement:
Je les ai déjà utilisés pour effectuer quelque chose de similaire.
Dans mon cas, j'ai défini une classe spécifique avec des méthodes définies qui étaient nécessaires. Une fois que j'ai chargé le module, je vérifierais si la classe était dans le module, puis je créerais une instance de cette classe, quelque chose comme ceci:
la source
expected_class
donc vous pouvez le faire à laclass_inst = getattr(py_mod,expected_name)()
place.Utilisez le module imp ou la
__import__()
fonction plus directe .la source
De nos jours, vous devriez utiliser importlib .
Importer un fichier source
Les documents fournissent en fait une recette pour cela, et cela se passe comme suit:
De cette façon, vous pouvez accéder aux membres (par exemple, une fonction "
hello
") de votre modulepluginX.py
- dans cet extrait appelémodule
- sous son espace de noms; Par exemple,module.hello()
.Si vous souhaitez importer les membres (par exemple, "
hello
"), vous pouvez incluremodule
/pluginX
dans la liste des modules en mémoire:Importer un package
L'importation d'un package ( par exemple ,
pluginX/__init__.py
) sous votre répertoire actuel est en fait simple:la source
sys.modules[module_name] = module
à la fin de votre code si vous voulez pouvoirimport module_name
ensuiteSi vous le souhaitez dans vos locaux:
même fonctionnerait avec
globals()
la source
locals()
fonction intégrée avertit explicitement que "le contenu de ce dictionnaire ne doit pas être modifié".Vous pouvez utiliser
exec
:la source
as command_module
à la fin de la déclaration d'importation, puis fairecommand_module.run()
Similaire à la solution de @monkut mais réutilisable et tolérante aux erreurs décrite ici http://stamat.wordpress.com/dynamic-module-import-in-python/ :
la source
La pièce ci-dessous a fonctionné pour moi:
si vous voulez importer en shell-script:
la source
Par exemple, les noms de mes modules sont comme
jan_module
/feb_module
/mar_module
.la source
Ce qui suit a fonctionné pour moi:
Il charge les modules du dossier «modus». Les modules ont une seule classe avec le même nom que le nom du module. Par exemple, le fichier modus / modu1.py contient:
Le résultat est une liste de classes "adaptateurs" chargés dynamiquement.
la source
fl
? La définition de la boucle for est trop complexe. Le chemin est codé en dur (et par exemple, non pertinent). Il utilise python (__import__
) découragé , à quoi çafl[i]
sert? C'est fondamentalement illisible, et est inutilement complexe pour quelque chose qui n'est pas si difficile - voir la réponse la plus votée avec sa ligne unique.