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.
dir(__import__)
. Die fromlist sollte eine Liste von Namen sein, die "from name import ..." emuliert werden sollen.
importlib
: stackoverflow.com/a/54956419/687896