Wie kann ich ein Modul importieren, das seinen Namen dynamisch als Zeichenfolge erhält?
Lesezeit: 8 Minuten
Kamil Kissel
Ich schreibe eine Python-Anwendung, die einen Befehl als Argument verwendet, zum Beispiel:
$ python myapp.py command1
Ich möchte, dass die Anwendung erweiterbar ist, dh dass neue Module hinzugefügt werden können, die neue Befehle implementieren, ohne die Hauptanwendungsquelle ändern zu müssen. Der Baum sieht in etwa so aus:
Die Funktion importiert das Modul namemöglicherweise unter Verwendung des Gegebenen globals und locals um zu bestimmen, wie der Name in einem Paketkontext zu interpretieren ist. Das fromlist gibt die Namen von Objekten oder Untermodulen an, die aus dem durch angegebenen Modul importiert werden sollen name.
Das funktioniert gut, 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 ausdrücklich nicht auf die Verwendung von Eiern oder Erweiterungspunkten eingehen möchte. Dies ist kein Open-Source-Projekt und ich erwarte nicht, dass es “Plugins” gibt. Der Punkt besteht darin, den Hauptanwendungscode zu vereinfachen und die Notwendigkeit zu beseitigen, ihn jedes Mal zu modifizieren, wenn ein neues Befehlsmodul hinzugefügt wird.
Siehe auch: Wie importiere ich ein Modul mit dem vollständigen Pfad?
Was bedeutet fromlist=[“myapp.commands”] tun?
– Peter Müller
6. Juni 2012 um 10:29 Uhr
@PieterMüller: Geben Sie in einer Python-Shell Folgendes ein: dir(__import__). Die fromlist sollte eine Liste von Namen sein, um “from name import …” zu emulieren.
– Mawimawi
9. August 2012 um 7:13 Uhr
Modul aus Stringvariable importieren
– Sturm_m2138
12. August 2015 um 18:28 Uhr
Ab 2019 sollten Sie suchen importlib: stackoverflow.com/a/54956419/687896
Ein Problem bei dieser Lösung für das OP besteht darin, dass das Abfangen von Ausnahmen für ein oder zwei fehlerhafte „Befehls“-Module dazu führt, dass seine/ihre gesamte Befehls-App bei einer Ausnahme fehlschlägt. Persönlich würde ich für Schleife über jeden importieren einzeln verpackt in try: mods=__import__()\naußer ImportError als Fehler: report(error), damit andere Befehle weiter funktionieren, während die schlechten behoben werden.
– DevPlayer
8. April 2015 um 13:38 Uhr
Ein weiteres Problem bei dieser Lösung ist, wie Denis Malinovsky weiter unten hervorhebt, dass die Python-Dokumentation selbst davon abrät, sie zu verwenden __import__. Die 2.7-Dokumente: “Da diese Funktion für den Python-Interpreter und nicht für den allgemeinen Gebrauch gedacht ist, ist es besser, importlib.import_module() zu verwenden …” Bei Verwendung von python3, the imp Modul löst dieses Problem, wie Moncut weiter unten erwähnt.
– LiavK
8. Juli 2015 um 15:14 Uhr
@JohnWu warum brauchst du foreach wenn du. .. hast for element in und map() obwohl 🙂
– Kuhbert
19. Februar 2018 um 22:59 Uhr
Beachten Sie, dass die Karte in Python 3 NICHT funktioniert, da die Karte jetzt eine verzögerte Auswertung verwendet.
– schw
13. November 2018 um 21:52 Uhr
Denis Malinowski
Das empfohlen Weg für Python 2.7 und 3.1 und höher zu verwenden importlib Modul:
importlib.import_module(name, package=None)
Importieren Sie ein Modul. Das Namensargument gibt an, welches Modul absolut oder relativ importiert werden soll (z. B. entweder pkg.mod oder ..mod). Wenn der Name relativ angegeben wird, muss das Paketargument auf den Namen des Pakets gesetzt werden, das als Anker für die Auflösung des Paketnamens dienen soll (z import_module('..mod', 'pkg.subpkg') wird importieren pkg.mod).
z.B
my_module = importlib.import_module('os.path')
Von welcher Quelle oder Behörde empfohlen?
– Michelnik
8. April 2015 um 13:21 Uhr
Dokumentation rät gegen verwenden __import__ Funktion zugunsten des oben genannten Moduls.
– Denis Malinowski
9. April 2015 um 12:42 Uhr
Dies funktioniert gut für den Import os.path ; wie wäre es mit from os.path import *?
– Name G VU
12. Juni 2017 um 6:31 Uhr
Ich bekomme die Antwort hier stackoverflow.com/a/44492879/248616 dh. Berufung globals().update(my_module.__dict)
– Name G VU
12. Juni 2017 um 6:46 Uhr
@NamGVU, dies ist eine gefährliche Methode, da sie Ihre Globals verschmutzt und alle Bezeichner mit denselben Namen überschreiben kann. Der von Ihnen gepostete Link enthält eine bessere, verbesserte Version dieses Codes.
– Denis Malinowski
19. Juni 2017 um 17:11 Uhr
Mönch
Notiz: Kobold ist seit Python 3.4 zugunsten von veraltet importlib
Wie erwähnt die Kobold Modul bietet Ihnen Ladefunktionen:
Ich habe diese zuvor verwendet, um etwas Ähnliches durchzuführen.
In meinem Fall habe ich eine bestimmte Klasse mit definierten Methoden definiert, die erforderlich waren. Sobald ich das Modul geladen habe, würde ich prüfen, ob die Klasse im Modul enthalten ist, und dann eine Instanz dieser Klasse erstellen, etwa so:
Gute und einfache Lösung. Ich habe ein ähnliches geschrieben: stamat.wordpress.com/dynamic-module-import-in-python Aber Ihres hat einige Mängel: Was ist mit Ausnahmen? IOError und ImportError? Warum nicht zuerst nach der kompilierten Version und dann nach der Quellversion suchen. Das Erwarten einer Klasse verringert die Wiederverwendbarkeit in Ihrem Fall.
– stamat
30. Juni 2013 um 20:40 Uhr
In der Zeile, in der Sie MyClass im Zielmodul konstruieren, fügen Sie einen redundanten Verweis auf den Klassennamen hinzu. Es ist bereits eingespeichert expected_class also könntest du machen class_inst = getattr(py_mod,expected_name)() stattdessen.
– Andreas
16. Oktober 2013 um 7:11 Uhr
Beachten Sie, dass, wenn eine richtig übereinstimmende Byte-kompilierte Datei (mit dem Suffix .pyc oder .pyo) vorhanden ist, diese verwendet wird, anstatt die angegebene Quelldatei zu analysieren. https://docs.python.org/2/library/imp.html#imp.load_source
– cdosborn
30. Juni 2015 um 21:07 Uhr
Achtung: Diese Lösung funktioniert; das imp-Modul wird jedoch zugunsten von importlib veraltet sein, siehe imps Seite:
Auf diese Weise können Sie auf die Mitglieder zugreifen (z. B. eine Funktion “hello“) aus Ihrem Modul pluginX.py — in diesem Snippet wird aufgerufen module — unter seinem Namensraum; Z.B, module.hello().
Wenn Sie die Mitglieder importieren möchten (z. B. “hello“) können Sie einfügen module/pluginX in der In-Memory-Liste der Module:
sys.modules[module_name] = module
from pluginX import hello
hello()
Importieren Sie ein Paket
Importieren eines Pakets (z.B, pluginX/__init__.py) unter Ihrem aktuellen Verzeichnis ist eigentlich einfach:
import importlib
pkg = importlib.import_module('pluginX')
# check if it's all there..
def bla(mod):
print(dir(mod))
bla(pkg)
Wie erhalte ich über die exec einen Handle auf das Modul, damit ich (in diesem Beispiel) die Methode .run() aufrufen kann?
– Kamil Kisiel
19. November 2008 um 6:19 Uhr
Sie können dann getattr(myapp.commands, command) ausführen, um auf das Modul zuzugreifen.
– Greg Hewgill
19. November 2008 um 6:20 Uhr
… oder hinzufügen as command_module bis zum Ende der Import-Anweisung und dann tun command_module.run()
– oxfn
16. Oktober 2013 um 10:43 Uhr
In einigen Versionen von Python 3+ Exekutive wurde in eine Funktion mit dem zusätzlichen Vorteil umgewandelt, dass das in source erstellte Ergebnis, auf das verwiesen wird, im locals()-Argument von exec() gespeichert wird. Um die exec, auf die verwiesen wird, weiter von den lokalen Codeblock-Locals zu isolieren, können Sie Ihr eigenes Diktat bereitstellen, z. B. ein leeres, und die Referenzen mit diesem Diktat referenzieren oder dieses Diktat an andere Funktionen übergeben exec(source, gobals(), command1_dict) …. print(command1_dict[‘somevarible’])
– DevPlayer
8. April 2015 um 13:43 Uhr
14365500cookie-checkWie kann ich ein Modul importieren, das seinen Namen dynamisch als Zeichenfolge erhält?yes
Was bedeutet fromlist=[“myapp.commands”] tun?
– Peter Müller
6. Juni 2012 um 10:29 Uhr
@PieterMüller: Geben Sie in einer Python-Shell Folgendes ein:
dir(__import__)
. Die fromlist sollte eine Liste von Namen sein, um “from name import …” zu emulieren.– Mawimawi
9. August 2012 um 7:13 Uhr
Modul aus Stringvariable importieren
– Sturm_m2138
12. August 2015 um 18:28 Uhr
Ab 2019 sollten Sie suchen
importlib
: stackoverflow.com/a/54956419/687896– Brandt
13. März 2019 um 9:42 Uhr
Verwenden Sie nicht __import__ siehe Python-Doc verwenden ein importlib.import_module
– fcm
28. Juni 2019 um 15:00 Uhr