2011-10-24 1 views
9

Come posso sapere quale file sta importando un particolare file in python?Come sapere chi mi sta importando in python?

consideri il seguente esempio:

#a.py 
import cmn 
.... 

#b.py 
import cmn 
... 

#cmn.py 
#Here, I want to know which file (a.py or b.py) 
#is importing this one. 
#Is it possible to do this? 
... 

Tutti i file a.py, b.py e cmn.py sono nella stessa directory.

Perché voglio farlo?
In C/C++, hanno funzione di inclusione. Quello che voglio fare può essere illuminato dal codice C/C++.

//a.cpp 
.... 
#define SOME_STUFF .... 
#include "cmn.h" 

//b.cpp 
... 
#define SOME_STUFF .... 

#include "cmn.h" 

//cmn.h 
//Here, I'll define some functions/classes that will use the symbol define 
//in the a.cpp or b.cpp 
... 
....code refer to the SOME_STUFF..... 

In C/C++, possiamo utilizzare questo metodo per riutilizzare il codice sorgente.

Ora torna al mio codice Python.
Quando a.py import cmn.py, spero di eseguire cmn.py e cmn.py farà riferimento al simbolo definito in a.py.
Quando b.py importa cmn.py, spero di eseguire cmn.py e cmn.py farà riferimento al simbolo definito nel file b.py.

+3

Le librerie non devono dipendere da chi le importa, quindi in realtà non dovrebbe avere importanza. –

+4

@ MichaelAaronSafyan ha ragione. Tuttavia * può * essere fatto, come dimostrerò qui: http://stackoverflow.com/questions/7025538/in-python-if-a-module-calls-upon-another-modules-functions-is-it-it possibile-per/7025963 # 7025963. Tuttavia ... qual è il problema * reale * che stai cercando di risolvere? – Johnsyweb

+0

Cosa stai cercando di ottenere? Forse c'è un modo alternativo per ottenerlo senza dover accoppiare i tuoi file in questo modo. –

risposta

10

Il codice namedtuple nel modulo collezioni ha un esempio di come (e quando) per fare questo:

#cmn.py 
import sys 
print 'I am being imported by', sys._getframe(1).f_globals.get('__name__') 

Un limite di questo approccio è che il modulo più esterno è sempre denominato __main__. Se questo è il caso, il nome del modulo più esterno può essere determinato da sys.argv[0].

Una seconda limitazione è che se il codice che utilizza sys._getframe si trova nell'ambito del modulo, viene eseguito solo sulla prima importazione di cmn.py. Avresti bisogno di chiamare una funzione di qualche tipo dopo le importazioni se vuoi monitorare tutte le importazioni del modulo.

+0

Nota l'istruzione print viene eseguita solo alla prima importazione del modulo. Se si desidera catturare ogni importazione, è necessario chiamare una funzione da cmn.py dopo ogni importazione o utilizzare un hook di importazione. –

+1

Come si implementa qualcosa di simile per py3? – Rizo

+0

Questo ha funzionato per entrambe le versioni: https://stackoverflow.com/a/7151403/379159 – simno

3

Bene, questo è un tipo di cosa bizzarra da fare. Non hai spiegato perché vuoi sapere che cosa sta importando il tuo modulo, quindi non posso davvero aiutarti a risolvere il tuo problema. Inoltre non hai spiegato come o quando vuoi conoscere il modulo di importazione.

def who_imports(studied_module): 
    for loaded_module in sys.modules.values(): 
     for module_attribute in dir(loaded_module): 
      if getattr(loaded_module, module_attribute) is studied_module: 
       yield loaded_module 

Questo vi darà un iteratore su tutti i moduli che utilizzano il modulo come un oggetto di livello superiore. Non troverà moduli che fanno from cmn import * e l'elenco cambierà nel tempo.

>>> import os 
>>> for m in who_imports(os): 
...  print m.__name__ 
... 
site 
__main__ 
posixpath 
genericpath 
posixpath 
linecache 
+0

Sembra anche che non gestirà 'import foo as bar'. –

+1

@TavisRudd: in realtà gestisce 'import foo as bar':' who_imports (foo) 'restituirà il modulo che ha effettuato l'importazione. Questo perché il test è fatto su oggetti 'module' (tramite' is module'), e non sui nomi dei moduli. Si noti che i nomi dei moduli riportati sono i nomi originali, tuttavia (il programma che contiene l'importazione produrrà il nome 'pippo' se viene chiamato' who_imports (bar) '). – EOL

+0

@DietrichEpp: +1: modo pulito di rispondere alla domanda. La funzione 'who_imports()' potrebbe essere ottimizzata, però. Ad esempio, molti 'sys.modules.values ​​()' sono 'None' e potrebbero essere saltati. – EOL

1

È necessario installare un gancio di importazione che tenga traccia di tutte le importazioni. Vedi PEP 302 e http://docs.python.org/dev/py3k/library/importlib.html. Tuttavia, come sottolineato nei commenti sopra, c'è probabilmente un modo migliore per strutturare il codice.