2012-08-03 20 views
7

Desidero ottenere informazioni sui chiamanti di una funzione specifica in python. Ad esempio:Ottieni informazioni sui chiamanti di funzione in python

class SomeClass(): 
    def __init__(self, x): 
     self.x = x 
    def caller(self): 
     return special_func(self.x) 

def special_func(x): 
    print "My caller is the 'caller' function in an 'SomeClass' class." 

È possibile con python?

risposta

10

Sì, la funzione sys._getframe() consente di recuperare i frame dallo stack di esecuzione corrente, che è possibile quindi esaminare con i metodi e la documentazione disponibili nello inspect module; sarete alla ricerca di locali specifici nell'attributo f_locals, così come per le informazioni f_code:

import sys 
def special_func(x): 
    callingframe = sys._getframe(1) 
    print 'My caller is the %r function in a %r class' % (
     callingframe.f_code.co_name, 
     callingframe.f_locals['self'].__class__.__name__) 

Si noti che avrete bisogno di prendere un po 'cura di rilevare il tipo di informazioni che si trovano in ogni fotogramma.

+2

Dalla documentazione: 'Non è garantito ad esistere in tutte le implementazioni di Python.' – pradyunsg

3

Un esempio:

def f1(a): 
    import inspect 
    print 'I am f1 and was called by', inspect.currentframe().f_back.f_code.co_name 
    return a 

def f2(a): 
    return f1(a) 

recupererà il chiamante "immediato".

>>> f2(1) 
I am f1 and was called by f2 

E se non è stato chiamato da un altro che si ottiene (in IDLE):

>>> f1(1) 
I am f1 and was called by <module> 
+0

Grazie, Sono stato in grado di prendere questo e adattarlo alle mie esigenze. –

2

Grazie a Jon Clements risposta sono stato in grado di fare una funzione che restituisce un elenco ordinato di tutti i chiamanti:

def f1(): 
    names = [] 
    frame = inspect.currentframe() 
    ## Keep moving to next outer frame 
    while True: 
     try: 
      frame = frame.f_back 
      name = frame.f_code.co_name 
      names.append(name) 
     except: 
      break 
    return names 

e quando viene chiamato in una catena:

def f2(): 
    return f1() 

def f3(): 
    return f2() 

def f4(): 
    return f3() 

print f4() 

assomiglia a questo:

['f2', 'f3', 'f4', '<module>'] 

Nel mio caso ho filtrare nulla '<module>' e dopo, e poi prendere l'ultimo elemento ad essere il nome del chiamante originario.

o modificare il loop originale per salvare alla prima comparsa di qualsiasi nome che inizia con '<':

frame = frame.f_back 
name = frame.f_code.co_name 
if name[0] == '<': 
    break 
names.append(name)