2012-05-24 6 views
7

Sto provando a determinare il modulo corrente attuale di una funzione (come visto se importato da altrove), anche se il modulo corrente è "top level scripting environment" __main__.Python: determina il modulo corrente attuale (non __main__)

Può sembrare una cosa strana da fare, ma lo sfondo è che ho bisogno di serializzare una funzione e di non serializzarla (inclusi argomenti) su una macchina diversa, per la quale ho bisogno di assicurarmi il modulo corretto E NON __main__ viene importato prima della deserializzazione (altrimenti viene visualizzato un errore che indica AttributeError: 'module' object has no attribute my_fun).

Finora, ho provato inspection:

import inspect 
print inspect.getmodule(my_fun) 

che mi dà

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

naturalmente. Ho anche provato a trovare qualcosa di utile usando globals(), senza fortuna.

Quello che voglio veramente è <module 'example' from 'example.py'>. Suppongo che un modo hacky sarebbe quello di analizzarlo dal nome del file utilizzando qualcosa come

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

e poi trovare il modulo in base al nome sys.modules[m_name].

Esiste un metodo più pulito/migliore per farlo?

EDIT: Dopo aver appreso "FakeModule" di ipython e un po 'più googling, mi sono imbattuto this post, che descrive esattamente il problema che sto affrontando, compresa la mia soluzione attuale ad essa (che sta importando esplicitamente il modulo corrente import current_module e serializzazione current_module.my_fun anziché my_fun). Sto cercando di evitare questo, in quanto potrebbe non essere intuitivo per gli utenti del mio pacchetto.

+0

Avete già esaminato l'interno della libreria 'nose', in particolare il modulo 'importatore'? Il "naso" ha qualcosa di molto simile a questo, quindi potrebbe essere un buon posto per cercare l'ispirazione. –

risposta

3

Io in realtà sono imbattuto in questo stesso problema.

Quello che ho usato è stato:

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

che è effettivamente la stessa come "hack". Onestamente, penso che sia la soluzione migliore.

+0

Grazie Winston, è la soluzione sono andato con e non ho incontrato alcun problema brutto da allora. – soramimo

+0

Questo non funziona se si sta eseguendo lo script all'interno di una cartella, ad esempio, "bar/foo.py" – jwayne

+0

@jwayne, che cosa produce, invece? –

2

Un modo in cui è possibile farlo, possibilmente non nel modo migliore, ma funziona per me, consiste nell'importare i moduli con __import__ e utilizzare getattr in un modo simile al seguente.

(Qui sto usando alcune idee descritte in this post moduli su dinamicamente il carico.)

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() 

Dove modA.py assomiglia a questo:

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

Così si può vedere che stiamo ottenendo il nome del modulo che abbiamo importato e che stiamo ancora utilizzando gli oggetti e i metodi all'interno del modulo in modo normale. Quando ho eseguito questo ricevo il seguente:

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

Di nuovo, questo può o non può essere il modo "ideale", ma funziona bene e, per quanto posso dire non comporta alcun compromessi indesiderabili nell'alimentazione più casi. Spero che questo ti aiuti.

3

Penso che la soluzione originale sia la migliore e la più semplice. Se sei preoccupato di ciò che sembra controproducente per i tuoi utenti, avvolgilo in una bella funzione e documenta a cosa serve.

Quando si esegue un modulo come __main__, Python in realtà non lo associa al suo normale nome del modulo: Se si utilizza import example, il file verrà caricato una seconda volta come se fosse un modulo separato. In realtà questo accade probabilmente nel tuo caso, altrimenti non sarebbe in grado di trovare il modulo per nome in sys.modules: Modulo example e il modulo __main__ realmente sono oggetti di runtime separati, come scoprirete se si modifica in modo esplicito una variabile modulo uno di loro.

3

So che questo è vecchio, ma ho trovato una soluzione più semplice in python3 che ha lavorato per me. Per farla breve, c'è l'__spec__ dell'oggetto che memorizza anche il nome effettivo del modulo invece di essere "__main__".

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

Questo funziona solo quando è in esecuzione come modulo (con 'python -m'), altrimenti' __spec__' è 'None'. Ma è abbastanza buono per me! (Inoltre, per il mio caso d'uso, posso saltare 'inspect' e usare semplicemente' import __main__; print (__ principale __.__ spec __. Name) '.) –