2012-01-13 16 views
7

In C/C++, l'ho trovata spesso utile durante il debug per definire una macro, ad esempio ECHO(x), che stampa il nome della variabile e il suo valore (ad esempio ECHO(variable) potrebbe stampa variable 7). È possibile ottenere il nome della variabile in una macro utilizzando l'operatore 'stringification' # come descritto here. C'è un modo per farlo in Python?Trova il nome di una variabile Python passata a una funzione

In altre parole, vorrei una funzione

def echo(x): 
    #magic goes here 

che, se chiamato come foo=7; echo(foo) (o foo=7; echo('foo'), forse), sarebbe stampare foo 7. Mi rendo conto che è banale farlo se passo sia la variabile che il suo nome alla funzione, ma uso molte funzioni come questa durante il debug, e la ripetizione finisce sempre per irritarmi.

risposta

7
Non

davvero una soluzione, ma può essere a portata di mano (in ogni caso hai echo('foo') in questione):

def echo(**kwargs): 
    for name, value in kwargs.items(): 
     print name, value 

foo = 7 
echo(foo=foo) 

UPDATE: Soluzione per echo(foo) con inspect

import inspect 
import re 

def echo(arg): 
    frame = inspect.currentframe() 
    try: 
     context = inspect.getframeinfo(frame.f_back).code_context 
     caller_lines = ''.join([line.strip() for line in context]) 
     m = re.search(r'echo\s*\((.+?)\)$', caller_lines) 
     if m: 
      caller_lines = m.group(1) 
     print caller_lines, arg 
    finally: 
     del frame 

foo = 7 
bar = 3 
baz = 11 
echo(foo) 
echo(foo + bar) 
echo((foo + bar)*baz/(bar+foo)) 

uscita:

foo 7 
foo + bar 10 
(foo + bar)*baz/(bar+foo) 11 

Ha la chiamata più piccola, ma è sensibile alle nuove righe, ad es.:

echo((foo + bar)* 
     baz/(bar+foo)) 

stamperà:

baz/(bar+foo)) 11 
+0

Questa seconda soluzione è estremamente intelligente. Mentre sto lavorando su come funziona, ho trovato una domanda doppia [qui] (http://stackoverflow.com/questions/5503363/can-you-translate-this-debugging-macro-from-c-to-python) - sebbene la tua regex è un po 'più robusta della risposta simile data lì. – James

+0

ottima risposta, grazie. potresti spiegare brevemente come funziona la regex? – Ferguzz

+0

@Ferguzz, Cerca 'echo', quindi' \ s * '- 0 o molti spazi,' \ ('- parentesi,' (. +?) \) $ '- ricerca di non-greddy per tutti i simboli prima' \) '(parentesi) alla fine della riga (' $ '). Maggiori informazioni su http://www.regular-expressions.info/repeat.html. Puoi anche [eseguire il debug regexps] (http://stackoverflow.com/a/143636/1052325). Prova nella sessione interattiva di Python: 're.compile (r'echo \ s * \ ((. +?) \) $ ', Re.DEBUG)' – reclosedev

3

Ecco una soluzione che è digitare un po 'di più per chiamarlo. Essa si basa sulla funzione built-in locals:

def print_key(dictionary, key): 
    print key, '=', dictionary[key] 


foo = 7 
print_key(locals(), 'foo') 

Un echo con la semantica che hai menzionato è anche possibile, utilizzando il modulo inspect. Tuttavia, leggere gli avvertimenti nella documentazione di Inspect. Questo è un brutto attacco non portatile (non funziona in tutte le implementazioni di Python). Assicurati di usarlo solo per il debug.

L'idea è di esaminare il locals della funzione di chiamata. Il modulo inspect consente proprio questo: le chiamate sono rappresentate da oggetti frame collegati tra loro dall'attributo f_back. Sono disponibili le variabili locali e globali di ogni frame (ci sono anche i builtin, ma è improbabile che sia necessario stamparli).

Si consiglia di eliminare in modo esplicito eventuali oggetti frame di riferimento per impedire cicli di riferimento, come spiegato in inspect docs, ma questo non è strettamente necessario - la garbage collection li libererà prima o poi.

import inspect 

def echo(varname): 
    caller = inspect.currentframe().f_back 
    try: 
     value = caller.f_locals[varname] 
    except KeyError: 
     value = caller.f_globals[varname] 
    print varname, '=', value 
    del caller 

foo = 7 
echo('foo') 
Problemi correlati