2012-05-24 3 views
7

Ich versuche, die tatsächliche aktuelle Modul einer Funktion zu ermitteln (wie gesehen, wenn von anderswo importiert), auch wenn das aktuelle Modul ist "top level scripting environment" __main__.Python: tatsächliche aktuelle Modul (nicht __main__)

Es mag wie eine komische Sache zu tun, aber der Hintergrund ist, dass ich eine Funktion serialisieren und esserialisieren (einschließlich Argumente) auf einer anderen Maschine, für die ich sicherstellen muss, dass das richtige Modul und nicht __main__ wird vor dem Deserialisieren importiert (sonst bekomme ich eine Fehlermeldung mit AttributeError: 'module' object has no attribute my_fun).

Bisher habe ich inspection versucht:

import inspect 
print inspect.getmodule(my_fun) 

die mich

<module '__main__' from 'example.py'> 

natürlich gibt. Ich habe auch versucht, etwas nützlich zu finden mit globals(), kein Glück.

Was ich wirklich will, ist <module 'example' from 'example.py'>. Ich nehme an, ein hacky Weg, um es aus dem Dateinamen so etwas wie

m_name = __main__.__file__.split("/")[-1].replace(".pyc","") 

und dann finden Sie das Modul mit Namen sys.modules[m_name] mit zu analysieren wäre.

Gibt es einen saubereren/besseren Weg, dies zu tun?

EDIT: Nach dem Lernen über ipython der „FakeModule“ und ein bisschen mehr googeln, Ich habe accross this post, die genau das Problem beschreibt, dass ich bin vor, auch meine aktuelle Lösung, um es (die explizit das aktuelle Modul importiert import current_module und Serialisierung current_module.my_fun anstelle von my_fun). Ich versuche, dies zu vermeiden, da es für die Benutzer meines Pakets nicht intuitiv ist.

+0

Haben Sie sich schon einmal die Interna der 'nose' Bibliothek angeschaut, speziell das' importer' Modul? "nose" macht einige Dinge sehr ähnlich, also könnte es ein guter Ort sein, um nach Inspiration zu suchen. –

Antwort

3

Ich lief tatsächlich über das gleiche Problem.

Was ich verwendet wurde:

return os.path.splitext(os.path.basename(__main__.__file__))[0] 

, die effektiv das gleiche wie Ihr ist "Hack". Ehrlich gesagt, denke ich, es ist die beste Lösung.

+0

Dank Winston, es ist die Lösung, mit der ich ging, und ich habe seitdem keine unangenehmen Probleme bekommen. – soramimo

+0

Dies funktioniert nicht, wenn Sie Ihr Skript in einem Ordner ausführen, z. B. "bar/foo.py" – jwayne

+0

@jwayne, was produziert es stattdessen? –

2

Eine Möglichkeit, dies zu tun - möglicherweise nicht der beste Weg, aber es funktioniert für mich - ist Ihre Module mit __import__ zu importieren und getattr auf eine Art und Weise wie folgt zu verwenden.

(Hier bin ich mit ein paar in this post beschriebenen Ideen dynamisch geladen Module.)

def dynamic_import(name): 
    mod = __import__(name) 
    components = name.split('.') 
    for comp in components[1:]: 
     mod = getattr(mod, comp) 
    return mod 

tmodule = dynamic_import('modA') 
# Print the module name 
print tmodule 
# Use the module's contents 
t = tmodule.myObject() 
t.someMethod() 

Wo modA.py wie folgt aussieht:

class myObject(): 
    def someMethod(self): 
     print "I am module A" 

So können Sie sehen, wir bekommen Der Name des Moduls, das wir importiert haben, und die Verwendung der Objekte und Methoden im Modul auf normale Weise. Als ich das laufen bekomme ich folgendes:

python experiment.py 
<module 'modA' from 'modA.pyc'> 
I am module A 

Wiederum kann dieser oder auch nicht die „ideale“ Art und Weise sein, aber es funktioniert gut und soweit ich keine unerwünschten Kompromissen in den meisten mit sich bringen wird sagen können, Fälle. Hoffe das hilft.

3

Ich denke, dass Ihre ursprüngliche Lösung am besten und einfachsten ist. Wenn Sie sich Sorgen machen, dass es für Ihre Benutzer nicht intuitiv ist, verpacken Sie es in eine nette Funktion und dokumentieren Sie, wofür es gedacht ist.

Wenn Sie ein Modul als __main__ ausführen, assoziieren Python es wirklich nicht mit seinem normalen Modulnamen: Wenn Sie import example, wird es die Datei ein zweites Mal als ob es ein separates Modul ist. Dies passiert wahrscheinlich in Ihrem Fall, sonst würden Sie Ihr Modul nicht namentlich in sys.modules finden: Modul example und Modul __main__ sind wirklich separate Laufzeitobjekte, wie Sie herausfinden werden, wenn Sie explizit eine Modulvariable in ändern einer von ihnen.

3

Ich weiß, das ist veraltet, aber ich fand eine einfachere Lösung in Python3, die für mich funktionierte. Lange Rede, kurzer Sinn, da ist das __spec__ des Objekts, das auch den eigentlichen Modulnamen speichert, anstatt "__main__" zu sein.

import inspect 
if obj.__class_.__module__ == "__main__": 
    print(inspect.getmodule(obj).__spec__.name) 
+0

Das funktioniert nur, wenn es als Modul ausgeführt wird (mit 'python -m'), sonst' __spec__' ist 'None'. Aber das ist gut genug für mich! (Auch für meinen Anwendungsfall kann ich "inspect" überspringen und einfach "import __main__; print (__ main __.__ spec __. Name)" verwenden.) –