Dynamisch Module Nachladen wenn die Namen erst zur Laufzeit bekannt sind?

Hi Liste, Was ist der eleganteste Weg um dynamisch Module aus einem Paket nachzuladen wenn die Modulnamen erst zur Laufzeit feststehen? Als uneleganteste Lösung könnte man bei Programmstart alle Module eines Paketes laden (wobei zur Zeit der Programmierung die Namen noch nicht feststehen), also sowas wie import paket.* oder from paket import * was ja leider nicht geht. Besser wäre wenn bei Nutzereingabe der string genommen wird und sowas wie from paket import eingabe das könnte man mit exec sicher noch irgendwie machen, aber kennt jemand ne elegantere Lösung? Hintergrund ist eine Nutzanwendung in dem in einem Paket nur Module sind die eine Klasse enthalten die alle von der selben Klasse abgeleitet sind. Je nach Nutzereingabe soll die jeweilige Klasse geladen werden. Sowas wie ein Plugin-System eben. Schön wäre es auch wenn man bei neuer Eingabe das alte Modul wieder entladen könnte... Schöne Grüße, Bastian -- Bastian Venthur http://venthur.de Debian Developer venthur at debian org

Hallo Bastian, die wesentlichen Funktionen für Deinen Anwendungsfall sind: sModName = Modulname dirnames = Liste mit weiteren Suchpfaden Modul finden: (file, pathname, description) = imp.find_module(sModName, dirnames) Modul laden: thisLib = imp.load_module(sModName, file, pathname, description) Findet sich im Modul imp. Damit lässt sich problemlos ein Plugin-System bauen. 'n bisschen Config, try/except und "fertich..." Viele Grüße, Andrew

Hallo,
Modul finden: (file, pathname, description) = imp.find_module(sModName, dirnames)
Interessant wäre noch, eine Liste der Modul in einem Verzeichnis zu bekommen. Irgendwelche Ideen ausser glob.glob('*.py') (und ähnliches)? -- Schönen Gruß - Regards Hartmut Goebel Goebel Consult Spezialist für IT-Sicherheit in komplexen Umgebungen http://www.goebel-consult.de

-----Ursprüngliche Nachricht----- Von: python-de-bounces@python.net [mailto:python-de-bounces@python.net] Im Auftrag von Hartmut Goebel Gesendet: Donnerstag, 15. November 2007 15:21 An: Die Deutsche Python Mailingliste Betreff: Re: [Python-de] Dynamisch Module Nachladen wenn die Namen erst zur Laufzeit bekannt sind?
Hallo,
Modul finden: (file, pathname, description) = imp.find_module(sModName, dirnames)
Interessant wäre noch, eine Liste der Modul in einem Verzeichnis zu bekommen. Irgendwelche Ideen ausser glob.glob('*.py') (und ähnliches)?
Ich hab so ein Plugin-System bereits mal implementiert (der Codeauszug ist aus dem Modul): Ich suche alle Dateien mit ".py" in einem Verzeichnis und versuche das Modul zu laden (try/except). Klappt das dann wird das Modul einer Liste von Modulen hinzugefügt auf die man später generisch verweisen kann. Zusätzlich habe ich noch Funktionen gebaut die die Doc-Strings nach bestimmten Mustern durchsuchen um z.B. speziell gekennzeichnete Klassen noch vor der Instanziierung identifizeren und gesondert behandeln zu können. Die Idee war das in einem Modul eine beliebig benannte Klasse als "Factory" gekennzeichnet und in einer gesonderten Liste gehalten wird. Ich war so von der Docstring-Idee fasziniert das ich vergessen habe das ich's mir mit einem "isinstance" Test und einer gemeinsamen Basisklasse (die eh notwendig ist) den Aufwand hätte sparen können... Um die Frage zu benantworten: was besseres als auf ein Verzeichnis per Muster zuzugreifen ist mir auch nicht eingefallen :-) Viele Grüße, Andrew

Andrew Smart schrieb:
Ich suche alle Dateien mit ".py" in einem Verzeichnis und versuche das Modul zu laden (try/except). Klappt das dann wird das Modul einer Liste von Modulen hinzugefügt auf die man später generisch verweisen kann.
Das klappt aber nicht mit Packages oder mit Modulen, bei denen der Quelltext nicht vorhanden ist. ;-(
Idee war das in einem Modul eine beliebig benannte Klasse als "Factory" gekennzeichnet und in einer gesonderten Liste gehalten wird. ... Ich war so von der Docstring-Idee fasziniert das ich vergessen habe das ich's mir mit einem "isinstance" Test und einer gemeinsamen Basisklasse (die eh notwendig ist) den Aufwand hätte sparen können...
:-) Das ist auch noch einfacher und deutlicher, weil die Information "das ist eine Factory" dann auch klar erkennbar ist.
Um die Frage zu benantworten: was besseres als auf ein Verzeichnis per Muster zuzugreifen ist mir auch nicht eingefallen :-)
Schade. -- Schönen Gruß - Regards Hartmut Goebel Goebel Consult Spezialist für IT-Sicherheit in komplexen Umgebungen http://www.goebel-consult.de

Von: python-de-bounces@python.net [mailto:python-de-bounces@python.net] Im Auftrag von Hartmut Goebel Gesendet: Donnerstag, 15. November 2007 17:31 An: Die Deutsche Python Mailingliste Betreff: Re: [Python-de] Dynamisch Module Nachladen wenn die Namen erst zur Laufzeit bekannt sind?
Andrew Smart schrieb:
Das klappt aber nicht mit Packages oder mit Modulen, bei denen der Quelltext nicht vorhanden ist. ;-(
Dafür bietet sich __import__ an. Bei quellenlosen Plugins Müsste man mal probieren statt .py .pyc zu laden. Hab ich aber noch nicht ausprobiert.
:-) Das ist auch noch einfacher und deutlicher, weil die Information "das ist eine Factory" dann auch klar erkennbar ist.
Yep. Auf der anderen Seite könnt's sein das ich diese Scan- Funktionalität nochmal brauche. Irgendein obskurer Anwendungsfall lässt sich da bestimmt kreieren... So was wie "als Pluginentwickler müssen die die Quadratwurzel der Primzahl die ihrem Geburtsjahr am nächsten gelegen ist als md5-hashkey zur Verifizierung im Docstring des Moduls hinterlegen, sonst wird ihr Plugin nicht geladen..." ;-) Viele Grüße, Andrew

Andrew Smart schrieb:
Dafür bietet sich __import__ an. Bei quellenlosen Plugins Müsste man mal probieren statt .py .pyc zu laden. Hab ich aber noch nicht ausprobiert.
Der Import ist doch nicht das Problem. Das Problem ist vorher festzustellen, welche Module/Packages es gibt. -- Schönen Gruß - Regards Hartmut Goebel Goebel Consult Spezialist für IT-Sicherheit in komplexen Umgebungen http://www.goebel-consult.de

-----Ursprüngliche Nachricht----- Von: python-de-bounces@python.net [mailto:python-de-bounces@python.net] Im Auftrag von Hartmut Goebel Gesendet: Donnerstag, 15. November 2007 21:37 An: Die Deutsche Python Mailingliste Betreff: Re: [Python-de] Dynamisch Module Nachladen wenn die Namen erst zur Laufzeit bekannt sind?
Andrew Smart schrieb:
Dafür bietet sich __import__ an. Bei quellenlosen Plugins Müsste man mal probieren statt .py .pyc zu laden. Hab ich aber noch nicht ausprobiert.
Der Import ist doch nicht das Problem. Das Problem ist vorher festzustellen, welche Module/Packages es gibt.
Da hast Du auch wieder recht. Was ich meinte war: __import__ ist besser geeignet für Packages als load_module. Zitat Hilfe von "find_module": This function does not handle hierarchical module names (names containing dots). In order to find P.M, that is, submodule M of package P, use find_module() and load_module() to find and load package P, and then use find_module() with the path argument set to P.__path__. When P itself has a dotted name, apply this recipe recursively. Klingt umständlich. Also __import__. Packages identifizieren: Alternativ entweder nach __init__.py suchen (weil das dann ein Package andeutet), oder find_module verwenden (s.o.) und dann per __import__ versuchen zu laden. Wie auch immer... gehen tuts :-) Viele Grüße, Andrew

Hi, das geht ganz einfach, indem man die eingebaute Funktion __import__ verwendet. Es ist sogar so, daß import seinerseits wiederum auf __import__ basiert. Siehe: http://docs.python.org/lib/built-in-funcs.html HTH, Gerald Bastian Venthur schrieb:
Hi Liste,
Was ist der eleganteste Weg um dynamisch Module aus einem Paket nachzuladen wenn die Modulnamen erst zur Laufzeit feststehen?
Als uneleganteste Lösung könnte man bei Programmstart alle Module eines Paketes laden (wobei zur Zeit der Programmierung die Namen noch nicht feststehen), also sowas wie
import paket.* oder from paket import *
was ja leider nicht geht.
Besser wäre wenn bei Nutzereingabe der string genommen wird und sowas wie
from paket import eingabe
das könnte man mit exec sicher noch irgendwie machen, aber kennt jemand ne elegantere Lösung?
Hintergrund ist eine Nutzanwendung in dem in einem Paket nur Module sind die eine Klasse enthalten die alle von der selben Klasse abgeleitet sind. Je nach Nutzereingabe soll die jeweilige Klasse geladen werden. Sowas wie ein Plugin-System eben. Schön wäre es auch wenn man bei neuer Eingabe das alte Modul wieder entladen könnte...
Schöne Grüße,
Bastian

Super, das geht ja sogar noch viel schneller. Danke! Gibts jetzt noch was äquivalentes um die gleichnamige Klasse aus dem Modul zu bekommen? Angenommen, jedes Modul enthält eine Gleichnamige Klasse (die wie gesagt alle von der gleichen Klasse abstammen). Jetzt hab ich das Modul Foo dynamisch geladen, aber wie bekomme ich dynamisch ein Objekt Foo.Foo ohne exec zu bemühen? Schöne Grüße, Bastian On 15.11.2007 15:20 schrieb Gerald Klix:
Hi, das geht ganz einfach, indem man die eingebaute Funktion __import__ verwendet. Es ist sogar so, daß import seinerseits wiederum auf __import__ basiert.
Siehe: http://docs.python.org/lib/built-in-funcs.html
HTH, Gerald
Bastian Venthur schrieb:
Hi Liste,
Was ist der eleganteste Weg um dynamisch Module aus einem Paket nachzuladen wenn die Modulnamen erst zur Laufzeit feststehen?
Als uneleganteste Lösung könnte man bei Programmstart alle Module eines Paketes laden (wobei zur Zeit der Programmierung die Namen noch nicht feststehen), also sowas wie
import paket.* oder from paket import *
was ja leider nicht geht.
Besser wäre wenn bei Nutzereingabe der string genommen wird und sowas wie
from paket import eingabe
das könnte man mit exec sicher noch irgendwie machen, aber kennt jemand ne elegantere Lösung?
Hintergrund ist eine Nutzanwendung in dem in einem Paket nur Module sind die eine Klasse enthalten die alle von der selben Klasse abgeleitet sind. Je nach Nutzereingabe soll die jeweilige Klasse geladen werden. Sowas wie ein Plugin-System eben. Schön wäre es auch wenn man bei neuer Eingabe das alte Modul wieder entladen könnte...
Schöne Grüße,
Bastian
_______________________________________________ python-de maillist - python-de@python.net http://python.net/mailman/listinfo/python-de
-- Bastian Venthur http://venthur.de Debian Developer venthur at debian org

Bastian Venthur schrieb:
Jetzt hab ich das Modul Foo dynamisch geladen, aber wie bekomme ich dynamisch ein Objekt Foo.Foo ohne exec zu bemühen?
getattr() ? -- Schönen Gruß - Regards Hartmut Goebel Goebel Consult Spezialist für IT-Sicherheit in komplexen Umgebungen http://www.goebel-consult.de

Am 15.11.2007 um 16:52 schrieb Bastian Venthur:
Super, das geht ja sogar noch viel schneller. Danke!
Gibts jetzt noch was äquivalentes um die gleichnamige Klasse aus dem Modul zu bekommen?
Angenommen, jedes Modul enthält eine Gleichnamige Klasse (die wie gesagt alle von der gleichen Klasse abstammen).
Jetzt hab ich das Modul Foo dynamisch geladen, aber wie bekomme ich dynamisch ein Objekt Foo.Foo ohne exec zu bemühen?
In [3]: getattr(string, 'whitespace') Out[3]: '\t\n\x0b\x0c\r ' In [4]: getattr(string, 'rfind') Out[4]: <function rfind at 0x5a38b0> HTH, __Janko -- Janko Hauser email: jhauser@zscout.de mobile: +49 1721 641552

Hi Bastian, versuchs mal mit sowas wie: def loadPlugin( name ): return getattr( __import__( name ), name ) Mit ein wenig error handling sollte es das schon tun. Bis denne, Gerald Bastian Venthur schrieb:
Super, das geht ja sogar noch viel schneller. Danke!
Gibts jetzt noch was äquivalentes um die gleichnamige Klasse aus dem Modul zu bekommen?
Angenommen, jedes Modul enthält eine Gleichnamige Klasse (die wie gesagt alle von der gleichen Klasse abstammen).
Jetzt hab ich das Modul Foo dynamisch geladen, aber wie bekomme ich dynamisch ein Objekt Foo.Foo ohne exec zu bemühen?
Schöne Grüße,
Bastian
On 15.11.2007 15:20 schrieb Gerald Klix:
Hi, das geht ganz einfach, indem man die eingebaute Funktion __import__ verwendet. Es ist sogar so, daß import seinerseits wiederum auf __import__ basiert.
Siehe: http://docs.python.org/lib/built-in-funcs.html
HTH, Gerald
Bastian Venthur schrieb:
Hi Liste,
Was ist der eleganteste Weg um dynamisch Module aus einem Paket nachzuladen wenn die Modulnamen erst zur Laufzeit feststehen?
Als uneleganteste Lösung könnte man bei Programmstart alle Module eines Paketes laden (wobei zur Zeit der Programmierung die Namen noch nicht feststehen), also sowas wie
import paket.* oder from paket import *
was ja leider nicht geht.
Besser wäre wenn bei Nutzereingabe der string genommen wird und sowas wie
from paket import eingabe
das könnte man mit exec sicher noch irgendwie machen, aber kennt jemand ne elegantere Lösung?
Hintergrund ist eine Nutzanwendung in dem in einem Paket nur Module sind die eine Klasse enthalten die alle von der selben Klasse abgeleitet sind. Je nach Nutzereingabe soll die jeweilige Klasse geladen werden. Sowas wie ein Plugin-System eben. Schön wäre es auch wenn man bei neuer Eingabe das alte Modul wieder entladen könnte...
Schöne Grüße,
Bastian
_______________________________________________ python-de maillist - python-de@python.net http://python.net/mailman/listinfo/python-de

Danke für die vielen Hinweise mit getattr, irgendwie steh ich trotzdem noch aufm Schlauch. Ich möchte ein tatsächliches Objekt zurückhaben, ich hab das gefühl ich bekomme mit: On 15.11.2007 17:33 schrieb Gerald Klix:
def loadPlugin( name ): return getattr( __import__( name ), name )
nur den Typen zurück, aber kein "lebendes" Objekt. Wenn "mod" mein erfolgreich dynamisch geladenes Modlul ist, funktioniert zwar self.plugin = mod.Foo() aber nicht self.plugin = getattr(mod, "Foo") Das erste nützt mir aber nix, weil "Foo" ja erst zur Laufzeit gegeben ist. Das zweite wird zwar anstandslos ausgeführt, aber wenn ich eine Funktion von plugin ausführen möchte bekomm ich immer die Fehlermeldung TypeError: unbound method bar() must be called with Foo instance as first argument (got type instance instead) Schöne Grüße, Bastian
Mit ein wenig error handling sollte es das schon tun.
Bis denne, Gerald
Bastian Venthur schrieb:
Super, das geht ja sogar noch viel schneller. Danke!
Gibts jetzt noch was äquivalentes um die gleichnamige Klasse aus dem Modul zu bekommen?
Angenommen, jedes Modul enthält eine Gleichnamige Klasse (die wie gesagt alle von der gleichen Klasse abstammen).
Jetzt hab ich das Modul Foo dynamisch geladen, aber wie bekomme ich dynamisch ein Objekt Foo.Foo ohne exec zu bemühen?
Schöne Grüße,
Bastian
On 15.11.2007 15:20 schrieb Gerald Klix:
Hi, das geht ganz einfach, indem man die eingebaute Funktion __import__ verwendet. Es ist sogar so, daß import seinerseits wiederum auf __import__ basiert.
Siehe: http://docs.python.org/lib/built-in-funcs.html
HTH, Gerald
Bastian Venthur schrieb:
Hi Liste,
Was ist der eleganteste Weg um dynamisch Module aus einem Paket nachzuladen wenn die Modulnamen erst zur Laufzeit feststehen?
Als uneleganteste Lösung könnte man bei Programmstart alle Module eines Paketes laden (wobei zur Zeit der Programmierung die Namen noch nicht feststehen), also sowas wie
import paket.* oder from paket import *
was ja leider nicht geht.
Besser wäre wenn bei Nutzereingabe der string genommen wird und sowas wie
from paket import eingabe
das könnte man mit exec sicher noch irgendwie machen, aber kennt jemand ne elegantere Lösung?
Hintergrund ist eine Nutzanwendung in dem in einem Paket nur Module sind die eine Klasse enthalten die alle von der selben Klasse abgeleitet sind. Je nach Nutzereingabe soll die jeweilige Klasse geladen werden. Sowas wie ein Plugin-System eben. Schön wäre es auch wenn man bei neuer Eingabe das alte Modul wieder entladen könnte...
Schöne Grüße,
Bastian
_______________________________________________ python-de maillist - python-de@python.net http://python.net/mailman/listinfo/python-de
_______________________________________________ python-de maillist - python-de@python.net http://python.net/mailman/listinfo/python-de
-- Bastian Venthur http://venthur.de Debian Developer venthur at debian org

ok habs: self.plugin = getattr(mod, "Foo")() oder lesbarer self.plugin = getattr(mod, "Foo") self.plugin = self.plugin() wars gewesen. Danke für eure Hilfe und schönen Abend, Bastian On 15.11.2007 19:20 schrieb Bastian Venthur:
Danke für die vielen Hinweise mit getattr, irgendwie steh ich trotzdem noch aufm Schlauch. Ich möchte ein tatsächliches Objekt zurückhaben, ich hab das gefühl ich bekomme mit:
On 15.11.2007 17:33 schrieb Gerald Klix:
def loadPlugin( name ): return getattr( __import__( name ), name )
nur den Typen zurück, aber kein "lebendes" Objekt.
Wenn "mod" mein erfolgreich dynamisch geladenes Modlul ist, funktioniert zwar
self.plugin = mod.Foo()
aber nicht
self.plugin = getattr(mod, "Foo")
Das erste nützt mir aber nix, weil "Foo" ja erst zur Laufzeit gegeben ist.
Das zweite wird zwar anstandslos ausgeführt, aber wenn ich eine Funktion von plugin ausführen möchte bekomm ich immer die Fehlermeldung
TypeError: unbound method bar() must be called with Foo instance as first argument (got type instance instead)
Schöne Grüße,
Bastian
Mit ein wenig error handling sollte es das schon tun.
Bis denne, Gerald
Bastian Venthur schrieb:
Super, das geht ja sogar noch viel schneller. Danke!
Gibts jetzt noch was äquivalentes um die gleichnamige Klasse aus dem Modul zu bekommen?
Angenommen, jedes Modul enthält eine Gleichnamige Klasse (die wie gesagt alle von der gleichen Klasse abstammen).
Jetzt hab ich das Modul Foo dynamisch geladen, aber wie bekomme ich dynamisch ein Objekt Foo.Foo ohne exec zu bemühen?
Schöne Grüße,
Bastian
On 15.11.2007 15:20 schrieb Gerald Klix:
Hi, das geht ganz einfach, indem man die eingebaute Funktion __import__ verwendet. Es ist sogar so, daß import seinerseits wiederum auf __import__ basiert.
Siehe: http://docs.python.org/lib/built-in-funcs.html
HTH, Gerald
Bastian Venthur schrieb:
Hi Liste,
Was ist der eleganteste Weg um dynamisch Module aus einem Paket nachzuladen wenn die Modulnamen erst zur Laufzeit feststehen?
Als uneleganteste Lösung könnte man bei Programmstart alle Module eines Paketes laden (wobei zur Zeit der Programmierung die Namen noch nicht feststehen), also sowas wie
import paket.* oder from paket import *
was ja leider nicht geht.
Besser wäre wenn bei Nutzereingabe der string genommen wird und sowas wie
from paket import eingabe
das könnte man mit exec sicher noch irgendwie machen, aber kennt jemand ne elegantere Lösung?
Hintergrund ist eine Nutzanwendung in dem in einem Paket nur Module sind die eine Klasse enthalten die alle von der selben Klasse abgeleitet sind. Je nach Nutzereingabe soll die jeweilige Klasse geladen werden. Sowas wie ein Plugin-System eben. Schön wäre es auch wenn man bei neuer Eingabe das alte Modul wieder entladen könnte...
Schöne Grüße,
Bastian
_______________________________________________ python-de maillist - python-de@python.net http://python.net/mailman/listinfo/python-de
_______________________________________________ python-de maillist - python-de@python.net http://python.net/mailman/listinfo/python-de
-- Bastian Venthur http://venthur.de Debian Developer venthur at debian org

Bastian Venthur schrieb:
On 15.11.2007 17:33 schrieb Gerald Klix:
def loadPlugin( name ): return getattr( __import__( name ), name )
nur den Typen zurück, aber kein "lebendes" Objekt.
Das kommt immer darauf an, was sich für ein Objekt sich hinter dem Namen verbirgt. Wenn das ein Typ (Du meinst wohl eine Klasse) ist, bekommst Du natürlich die Klasse. Um das "lebendige Objekt" zu bekommen, musst Du die Klasse erst instanzieren.
Wenn "mod" mein erfolgreich dynamisch geladenes Modlul ist, funktioniert zwar self.plugin = mod.Foo()
Das liefert Dir das Ergebnis der Funktion Foo(), bzw. eine Instanz der Klasse Foo, falls Foo eine Klasse ist.
aber nicht self.plugin = getattr(mod, "Foo")
Das leifert Dir das Objekt mit dem Namen Foo.
TypeError: unbound method bar() must be called with Foo instance as first argument (got type instance instead)
Ich vermute, Du willst self.plugin.bar() aufrufen. Klar, dass das _so_ nicht geht, den self.plugin ist die Klasse Foo, keine Instanz davon. Was Du möchtest ist wahrscheinlich self.plugin = getattr(mod, "Foo")() -- Schönen Gruß - Regards Hartmut Goebel Goebel Consult Spezialist für IT-Sicherheit in komplexen Umgebungen http://www.goebel-consult.de

On Thursday 15 November 2007 16:52:09 Bastian Venthur wrote:
Super, das geht ja sogar noch viel schneller. Danke!
Gibts jetzt noch was äquivalentes um die gleichnamige Klasse aus dem Modul zu bekommen?
Angenommen, jedes Modul enthält eine Gleichnamige Klasse (die wie gesagt alle von der gleichen Klasse abstammen).
Jetzt hab ich das Modul Foo dynamisch geladen, aber wie bekomme ich dynamisch ein Objekt Foo.Foo ohne exec zu bemühen?
getattr(modul, "Name") Diez

Jetzt hab ich das Modul Foo dynamisch geladen, aber wie bekomme ich dynamisch ein Objekt Foo.Foo ohne exec zu bemühen?
listOfModules -> dict mit den geladenen Modulen, mit Modulnamen als key sModule -> Gesuchtes Modul myModule = listOfModules[sModule] myObj = myModule.Foo() Wenn ich mich noch recht erinnere... Grüße, Andrew
participants (6)
-
Andrew Smart
-
Bastian Venthur
-
Diez B. Roggisch
-
Gerald Klix
-
Hartmut Goebel
-
Janko Hauser