Ottenere __name__ di chiamare il modulo della funzione in Python
-
11-09-2019 - |
Domanda
myapp/foo.py
Supponiamo che contiene:
def info(msg):
caller_name = ????
print '[%s] %s' % (caller_name, msg)
E myapp/bar.py
contiene:
import foo
foo.info('Hello') # => [myapp.bar] Hello
Voglio caller_name
da impostare per l'attributo __name__
delle funzioni di chiamata modulo (che è 'myapp.foo') in questo caso. Come si può fare?
Soluzione
Estrai il modulo ispezionare:
inspect.stack()
restituirà le informazioni di stack.
all'interno di una funzione, inspect.stack()[1]
tornerà pila del chiamante. Da lì, è possibile ottenere ulteriori informazioni sul nome della funzione del chiamante, moduli, ecc.
Si veda la documentazione per i dettagli:
http://docs.python.org/library/inspect.html
Inoltre, Doug Hellmann ha un interessante resoconto del modulo di ispezionare nella sua serie PyMOTW:
http://pymotw.com/2/inspect/index.html# modulo-ispezionare
EDIT: Ecco un po 'di codice che fa quello che si vuole, credo che:
def info(msg):
frm = inspect.stack()[1]
mod = inspect.getmodule(frm[0])
print '[%s] %s' % (mod.__name__, msg)
Altri suggerimenti
Di fronte a un problema simile, ho trovato che sys._current_frames () dal sys modulo contiene informazioni interessanti che possono aiutare, senza la necessità di importare ispezionare, almeno in specifici casi d'uso .
>>> sys._current_frames()
{4052: <frame object at 0x03200C98>}
È quindi possibile "cambiare" utilizzando f_back:
>>> f = sys._current_frames().values()[0]
>>> # for python3: f = list(sys._current_frames().values())[0]
>>> print f.f_back.f_globals['__file__']
'/base/data/home/apps/apricot/1.6456165165151/caller.py'
>>> print f.f_back.f_globals['__name__']
'__main__'
Per il nome del file è anche possibile usare f.f_back.f_code.co_filename, come suggerito da Mark Roddy sopra. Non sono sicuro dei limiti e delle avvertenze di questo metodo (più thread sarà molto probabilmente un problema), ma ho intenzione di usarlo nel mio caso.
Non consiglio fare questo, ma è possibile raggiungere il tuo obiettivo con il seguente metodo:
def caller_name():
frame=inspect.currentframe()
frame=frame.f_back.f_back
code=frame.f_code
return code.co_filename
Poi aggiornare il metodo esistente come segue:
def info(msg):
caller = caller_name()
print '[%s] %s' % (caller, msg)