2012-01-13 17 views
7

W języku C/C++, często uważałem za przydatne podczas debugowania zdefiniowanie makra, na przykład ECHO(x), które wypisuje nazwę zmiennej i jej wartość (np. ECHO(variable) może wydrukuj variable 7). Nazwę zmiennej można uzyskać w makrze za pomocą operatora "uszeregowania" # zgodnie z opisem here. Czy istnieje sposób na to w Pythonie?Znajdź nazwę zmiennej Pythona, która została przekazana do funkcji

Innymi słowy, chciałbym funkcję

def echo(x): 
    #magic goes here 

które, jeśli nazywa się foo=7; echo(foo) (lub foo=7; echo('foo'), być może), by wydrukować foo 7. Rozumiem, że jest to trywialne, jeśli przekazuję zarówno zmienną, jak i jej nazwę funkcji, ale często używam takich funkcji podczas debugowania, a powtarzanie zawsze mnie denerwuje.

Odpowiedz

7

Niezupełnie rozwiązanie, ale może być przydatny (i tak masz echo('foo') w pytaniu):

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

foo = 7 
echo(foo=foo) 

UPDATE: rozwiązanie dla echo(foo) z 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)) 

Wyjście:

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

Ma najmniejsze połączenie, ale jest wrażliwe na nowe linie, np.:

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

wypisze:

baz/(bar+foo)) 11 
+0

To drugie rozwiązanie jest bardzo mądry. Podczas pracy nad tym, jak to działa, znalazłem zduplikowane pytanie [tutaj] (http://stackoverflow.com/questions/5503363/can-you-translate-this-debugging-macro-from-c-to-python) - choć twoje regex jest trochę bardziej solidne niż podobna odpowiedź tam podana. – James

+0

świetna odpowiedź, dzięki. czy możesz krótko wyjaśnić, w jaki sposób działa regex? – Ferguzz

+0

@Ferguzz, Wyszukuje 'echo', następnie' \ s * '- 0 lub wiele spacji,' \ ('- nawiasy,' (. +?) \) $ '- non-greddy szuka wszystkich symboli przed. \) '(nawiasy) na końcu wiersza (' $ '). Więcej informacji na http://www.regular-expressions.info/repeat.html. Można również [debugowanie wyrażeń regularnych] (http://stackoverflow.com/a/143636/1052325). Spróbuj w interaktywnej sesji Pythona: 're.compile (r'echo \ s * \ ((. +?) \) $ ', Re.DEBUG)' – reclosedev

3
def echo(x): 
    import inspect 
    print "{0}: {1}".format(x, inspect.stack()[1][0].f_locals[x]) 
y = 123 
echo('y') 
# 'y: 123' 

Zobacz także: https://stackoverflow.com/a/2387854/16361

Należy pamiętać, że może to spowodować problemy z GW:

http://docs.python.org/library/inspect.html#the-interpreter-stack

Będzie również wyłączyć wyświetlanie osoby, które zostały spalone przez brudząc z ramkami, a może opuścić zły smak w twoich ustach. Ale to zadziała.

3

Oto rozwiązanie, które można nieco nazwać, aby je nazwać. Opiera się ona na wbudowanej funkcji locals:

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


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

echo z semantyki wspomniałeś jest również możliwe za pomocą modułu inspect. Jednak przeczytaj ostrzeżenia w dokumentacji kontrolnej. To jest brzydki nieprzenośny hack (nie działa we wszystkich implementacjach Pythona). Używaj go tylko do debugowania.

Chodzi o to, aby zaglądnąć do funkcji wywołującej . Moduł inspekcji pozwala właśnie na to: połączenia są reprezentowane przez obiekty ramek połączone atrybutem f_back. Dostępne są lokalne i globalne zmienne każdej klatki (są też wbudowane, ale prawdopodobnie nie będziesz ich potrzebował).

Możesz chcieć jawnie usunąć obiekty z ramkami referencyjnymi, aby zapobiec cyklom odniesienia, jak wyjaśniono w inspect docs, ale nie jest to absolutnie konieczne - odśmiecenie zwolni je wcześniej czy później.

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') 
Powiązane problemy