Dynamisches Importieren von Modulen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Dakkareth
User
Beiträge: 5
Registriert: Freitag 14. Mai 2004, 20:57

Hallo erstmal ;)

Als kleines Fun-Projekt arbeite ich ein bisschen an einem IRC-Bot herum. Die einzelnen Funktionen sind recht klein, aber dafür gibt es relativ viele und ich will als Endziel eigentlich den User selbst schnell und ohne besondere Python-Kenntnisse neue Funktionen hinzufügen lassen.

Fürs Erste würds mir aber schon genügen, wenn ich nicht jedesmal, wenn ich eine winzige Funktion ändere den ganzen Bot neu starten müsste mit Verbindung zum Server und allem. Ich dachte daher daran, die .py Dateien mit den Befehlsfunktionen als Module zu importieren und neu zu importieren, wenn ich was geändert habe. Bisher funktioniert das allerdings noch nicht :s

Ich häng einfach mal ein paar Code-Zeilen meines Versuchs an:

Code: Alles auswählen

    def load_module(self,name):
        try:
            exec 'import '+name
            exec 'dmerge('+name+'.commands,self.commands)'
            print self.commands
            return 'Loading '+name+' successful'
        except:
            return 'Error loading module'
        
    def unload_module(self,name):
        try:
            exec 'import '+name
            exec 'dunmerge('+name+'.commands,self.commands)'
            exec 'del '+name
            print self.commands
            return 'Unloading '+name+' successful'
        except:
            return 'Error unloading module'
Also. Zunächst mal stören mich die execs von einem ästhetischen Standpunkt her, mal ganz zu schweigen vom Sicherheitsaspekt. Aber würde es funktionieren, könnte man darüber hinwegsehen.

Die Idee ist, das mit name bezeichnete Modul zu importieren und mittels der von mir definierten Funktion dmerge(dictionary1,dictionary2) Befehlslisten des Bots (self.commands) und des Moduls zu vereinigen. Dabei sind die dictionaries von der Form {'say':cmd_say}, wobei cmd_say eine Funktion ist.

Unload soll die Befehlsliste wieder entfernen und sollte eigentlich das Modul 'unimportieren'.

Der erste Teil funktioniert auch gar nicht so schlecht - ich kann das Programm starten und später eine beliebige Datei mit Definitionen dazuladen. Der zweite Teil scheint jedoch nicht richtig zu funktionieren - wenn ich einmal Unload und wieder Load aufrufe, hab ich wieder die alten Funktionen, Änderungen seit dem ersten Load Aufruf sind nicht berücksichtigt.


Um es auf den Punkt zu bringen:

1. Kennt jemand eine elegantere Methode, zur Laufzeit definierte Module zu laden?

2. Falls das allein das Problem nicht behebt, was könnte ich tun um das angestrebte Verhalten zu erreichen?

3. Irgendwelche sonstigen Tipps?

Danke :)
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Hi Dakkareth,

ich würds mal beim reimport mit reload(module) versuchen.


Gruß

Dookie
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

Hi. Wirklich interessant sind in deinem Fall die Funktion __import__ und reload. Erste importiert ein Modul nach einem Namen (dein exec entfällt) und reload läd ein Modul erneut und berücksichtigt Änderungen (gibt das Modul als Object zurück, also z.B: so vorgehen math=reload(math)). Wenn du nun noch __import__ mit einem Dictionary kombinierst, kommst du ganz ohne exec aus, dabei sind die Schlüssel die Modulnamen und die Werte die Module selbst. Prinzip verstanden? Dann gibts hier mal eine überarbeitete Codefassung von dir :wink:

Code: Alles auswählen

moduldict={}
def load_module(self,name):
    try:
        moduldict[name]=__import__(name)
        dmerge(moduldict[name].commands,self.commands)
        print self.commands
        return 'Loading %s successful' % name
    except ImportError:
        return 'Error loading module'
    
def unload_module(self,name):
    try:
        dunmerge(moduldict[name].commands,self.commands)
        del moduldict[name]
        print self.commands
        return 'Unloading %s successful' % name
    except KeyError:
        return 'Error unloading module'
Warum importierst du eigentlich bei unload nocheinmal? Ist das notwendig? (habs mal rausgenommen)

hth, Milan
Dakkareth
User
Beiträge: 5
Registriert: Freitag 14. Mai 2004, 20:57

Warum importierst du eigentlich bei unload nocheinmal? Ist das notwendig? (habs mal rausgenommen)
Ich hatte es zuerst ohne, aber da konnte nicht auf das Modul zugreifen, also hab es einfach nochmal importiert.

Danke für die Antworten, Ich werd's morgen mal ausprobieren (bzw. nach dem nächsten Schlafzyklus). :)
Dakkareth
User
Beiträge: 5
Registriert: Freitag 14. Mai 2004, 20:57

Funktioniert wunderbar, danke für die Hilfe :)
Antworten