Ich schreibe eine Python-Anwendung, die als Befehl ein Argument verwendet, zum Beispiel:
$ python myapp.py command1
Ich möchte, dass die Anwendung erweiterbar ist, dh neue Module hinzufügen kann, die neue Befehle implementieren, ohne die Hauptanwendungsquelle ändern zu müssen. Der Baum sieht ungefähr so aus:
myapp/
__init__.py
commands/
__init__.py
command1.py
command2.py
foo.py
bar.py
Daher möchte ich, dass die Anwendung zur Laufzeit die verfügbaren Befehlsmodule findet und das entsprechende ausführt.
Python definiert eine __import__ -Funktion, die eine Zeichenfolge für einen Modulnamen verwendet :
__import __ (Name, global = Keine, Einheimische = Keine, fromlist = (), Ebene = 0)
Die Funktion importiert den Modulnamen und verwendet möglicherweise die angegebenen globalen und lokalen Elemente, um zu bestimmen, wie der Name in einem Paketkontext interpretiert werden soll. Die fromlist gibt die Namen von Objekten oder Submodulen an, die aus dem Modul mit Namen importiert werden sollen.
Quelle: https://docs.python.org/3/library/functions.html# import
Also habe ich momentan so etwas wie:
command = sys.argv[1]
try:
command_module = __import__("myapp.commands.%s" % command, fromlist=["myapp.commands"])
except ImportError:
# Display error message
command_module.run()
Dies funktioniert einwandfrei. Ich frage mich nur, ob es möglicherweise einen idiomatischeren Weg gibt, um das zu erreichen, was wir mit diesem Code tun.
Beachten Sie, dass ich speziell nicht darauf eingehen möchte, Eier oder Verlängerungspunkte zu verwenden. Dies ist kein Open-Source-Projekt und ich erwarte keine "Plugins". Der Punkt besteht darin, den Hauptanwendungscode zu vereinfachen und die Notwendigkeit zu beseitigen, ihn jedes Mal zu ändern, wenn ein neues Befehlsmodul hinzugefügt wird.
quelle
dir(__import__)
. Die fromlist sollte eine Liste von Namen sein, die "from name import ..." emuliert werden sollen.importlib
: stackoverflow.com/a/54956419/687896Antworten:
Mit Python älter als 2.7 / 3.1 machen Sie das so.
Bei neueren Versionen finden Sie
importlib.import_module
für Python 2 und und Python 3 .Sie können verwenden,
exec
wenn Sie möchten.Oder
__import__
Sie können eine Liste von Modulen importieren, indem Sie folgende Schritte ausführen:Direkt von Dive Into Python gerissen .
quelle
__init__
dieses Modul verwenden?__import__
. Die 2.7-Dokumente: "Da diese Funktion für den Python-Interpreter und nicht für den allgemeinen Gebrauch bestimmt ist, ist es besser, importlib.import_module () zu verwenden ..." Bei Verwendung von python3imp
löst das Modul dieses Problem, wie monkut unten erwähnt.foreach
wenn du hastfor element in
undmap()
obwohl :)Die empfohlene Methode für Python 2.7 und 3.1 und höher ist die Verwendung des
importlib
Moduls:z.B
quelle
__import__
Funktion zugunsten der oben genannten Moduls.os.path
; wie wäre esfrom os.path import *
?globals().update(my_module.__dict)
Wie bereits erwähnt, bietet Ihnen das imp- Modul Ladefunktionen :
Ich habe diese schon einmal benutzt, um etwas Ähnliches zu machen.
In meinem Fall habe ich eine bestimmte Klasse mit definierten Methoden definiert, die erforderlich waren. Sobald ich das Modul geladen habe, überprüfe ich, ob sich die Klasse im Modul befindet, und erstelle dann eine Instanz dieser Klasse, etwa so:
quelle
expected_class
sodass Sie diesclass_inst = getattr(py_mod,expected_name)()
stattdessen tun können .Verwenden Sie das imp-Modul oder die direktere
__import__()
Funktion.quelle
Heutzutage sollten Sie importlib verwenden .
Importieren Sie eine Quelldatei
Die Dokumente bieten tatsächlich ein Rezept dafür, und es geht so:
Auf diese Weise können Sie
hello
von Ihrem Modul auspluginX.py
- in diesem aufgerufenen Snippetmodule
- unter seinem Namespace auf die Mitglieder (z. B. eine Funktion " ") zugreifen . ZB ,module.hello()
.Wenn Sie die Mitglieder importieren möchten (z. B. "
hello
"), können Siemodule
/pluginX
in die speicherinterne Liste der Module aufnehmen:Importieren Sie ein Paket
Importieren eines Pakets ( zB ,
pluginX/__init__.py
) unter dem aktuellen Verzeichnis ist eigentlich ganz einfach:quelle
sys.modules[module_name] = module
am Ende des Codes , wenn Sie in der Lage sein wollen ,import module_name
danachWenn Sie es bei Ihren Einheimischen wollen:
das gleiche würde funktionieren mit
globals()
quelle
locals()
Funktion warnt ausdrücklich davor, dass "der Inhalt dieses Wörterbuchs nicht geändert werden sollte".Sie können verwenden
exec
:quelle
as command_module
am Ende der Importanweisung hinzufügen und dann tuncommand_module.run()
Ähnlich wie die Lösung von @monkut, jedoch wiederverwendbar und fehlertolerant, wie hier beschrieben. Http://stamat.wordpress.com/dynamic-module-import-in-python/ :
quelle
Das folgende Stück hat für mich funktioniert:
Wenn Sie in Shell-Skript importieren möchten:
quelle
Zum Beispiel sind meine Modulnamen wie
jan_module
/feb_module
/mar_module
.quelle
Folgendes hat bei mir funktioniert:
Es lädt Module aus dem Ordner 'modus'. Die Module haben eine einzelne Klasse mit demselben Namen wie der Modulname. ZB enthält die Datei modus / modu1.py:
Das Ergebnis ist eine Liste der dynamisch geladenen Klassen "Adapter".
quelle
fl
? Die for-Schleifendefinition ist zu komplex. Der Pfad ist fest codiert (und zum Beispiel irrelevant). Es verwendet entmutigtes Python (__import__
), wofür ist das allesfl[i]
? Dies ist im Grunde genommen nicht lesbar und für etwas, das nicht allzu schwer ist, unnötig komplex - siehe die Antwort mit der höchsten Abstimmung mit ihrem Einzeiler.