2012-03-30 17 views
5

W pewnych okolicznościach, chcę wydrukować wyjście debugowania stylu tak:nazwy drukowania zmiennych przekazanych do funkcji

# module test.py 
def f() 
    a = 5 
    b = 8 
    debug(a, b) # line 18 

Chcę funkcja debug wydrukować następujące:

debug info at test.py: 18 
function f 
a = 5 
b = 8 

Myślę, że powinno to być możliwe dzięki użyciu modułu inspekcji do zlokalizowania ramki stosu, a następnie znalezienia odpowiedniej linii, wyszukania kodu źródłowego w tej linii, uzyskania z niej nazw argumentów. Nazwę funkcji można uzyskać, przesuwając jedną klapkę w górę. (Wartości argumentów są łatwe do zdobycia: są przekazywane bezpośrednio do funkcji debug.)

Czy jestem na dobrej drodze? Czy istnieje przepis, do którego mogę się odnieść?

Odpowiedz

3

Można zrobić coś wzdłuż następujące wiersze:

import inspect 

def debug(**kwargs): 
    st = inspect.stack()[1] 
    print '%s:%d %s()' % (st[1], st[2], st[3]) 
    for k, v in kwargs.items(): 
    print '%s = %s' % (k, v) 

def f(): 
    a = 5 
    b = 8 
    debug(a=a, b=b) # line 12 

f() 

ten wypisuje:

test.py:12 f() 
a = 5 
b = 8 
+1

To jest ładne i proste! Ale nie miałbym nic przeciwko większej złożoności, jeśli oznacza to, że nie muszę powtarzać każdej nazwy zmiennej dwa razy: raz jako nazwa arg słowa kluczowego i raz jako wartość argumentu słowa kluczowego. – max

+0

Możesz spróbować wywołać 'debug (** locals())'. –

1

Ty zazwyczaj robi to dobrze, choć byłoby łatwiejsze w użyciu AOP dla tego rodzaju zadań. Zasadniczo, zamiast wywoływać "debugowanie" za każdym razem przy każdej zmiennej, można po prostu ozdobić kod aspektami, które wykonują określone czynności w określonych zdarzeniach, np. Po wprowadzeniu funkcji drukowania drukowanych zmiennych i jej nazwy.

Aby uzyskać więcej informacji, odwiedź stronę this i stare, aby uzyskać post.

1

Tak, jesteś na właściwej ścieżce. Możesz spojrzeć na inspect.getargspec, która zwróci nazwaną krotkę argumentów, varargs, słów kluczowych, wartości domyślnych przekazanych do funkcji.

import inspect 

def f(): 
    a = 5 
    b = 8 
    debug(a, b) 


def debug(a, b): 
    print inspect.getargspec(debug) 
f() 
0

To naprawdę trudne. Pozwól, że spróbuję podać bardziej kompletną odpowiedź, ponownie wykorzystując this code i podpowiedź na temat getargspec w odpowiedzi Senthila, która spowodowała, że ​​jakoś się wyzwalałem. Btw, getargspec jest już nieaktualne w Pythonie 3.0 i getfullarcspec should be used.

Działa to dla mnie na Python 3.1.2 zarówno jawne wywołanie funkcji debugowania i przy użyciu dekorator:

# from: https://stackoverflow.com/a/4493322/923794 
def getfunc(func=None, uplevel=0): 
    """Return tuple of information about a function 

    Go's up in the call stack to uplevel+1 and returns information 
    about the function found. 

    The tuple contains 
     name of function, function object, it's frame object, 
     filename and line number""" 
    from inspect import currentframe, getouterframes, getframeinfo 
    #for (level, frame) in enumerate(getouterframes(currentframe())): 
    # print(str(level) + ' frame: ' + str(frame)) 
    caller = getouterframes(currentframe())[1+uplevel] 
    # caller is tuple of: 
    # frame object, filename, line number, function 
    # name, a list of lines of context, and index within the context 
    func_name = caller[3] 
    frame = caller[0] 
    from pprint import pprint 
    if func: 
     func_name = func.__name__ 
    else: 
     func = frame.f_locals.get(func_name, frame.f_globals.get(func_name)) 
    return (func_name, func, frame, caller[1], caller[2]) 


def debug_prt_func_args(f=None): 
    """Print function name and argument with their values""" 
    from inspect import getargvalues, getfullargspec 
    (func_name, func, frame, file, line) = getfunc(func=f, uplevel=1) 
    argspec = getfullargspec(func) 
    #print(argspec) 
    argvals = getargvalues(frame) 
    print("debug info at " + file + ': ' + str(line)) 
    print(func_name + ':' + str(argvals)) ## reformat to pretty print arg values here 
    return func_name 



def df_dbg_prt_func_args(f): 
    """Decorator: dpg_prt_func_args - Prints function name and arguments 

    """ 
    def wrapped(*args, **kwargs): 
     debug_prt_func_args(f) 
     return f(*args, **kwargs) 
    return wrapped 

wykorzystania:

@df_dbg_prt_func_args 
def leaf_decor(*args, **kwargs): 
    """Leaf level, simple function""" 
    print("in leaf") 


def leaf_explicit(*args, **kwargs): 
    """Leaf level, simple function""" 
    debug_prt_func_args() 
    print("in leaf") 


def complex(): 
    """A complex function""" 
    print("start complex") 
    leaf_decor(3,4) 
    print("middle complex") 
    leaf_explicit(12,45) 
    print("end complex") 


complex() 

i druki:

start complex 
debug info at debug.py: 54 
leaf_decor:ArgInfo(args=[], varargs='args', keywords='kwargs', locals={'args': (3, 4), 'f': <function leaf_decor at 0x2aaaac048d98>, 'kwargs': {}}) 
in leaf 
middle complex 
debug info at debug.py: 67 
leaf_explicit:ArgInfo(args=[], varargs='args', keywords='kwargs', locals={'args': (12, 45), 'kwargs': {}}) 
in leaf 
end complex 

Dekorator oszukuje trochę: ponieważ w wrapped otrzymujemy to samo rguments jako funkcja sama w sobie nie ma znaczenia, że ​​odnajdujemy i raportujemy ArgSpec z wrapped w i debug_prt_func_args. Ten kod mógłby być nieco upiększony, ale teraz działa dobrze na prostych testach debugowania, których użyłem.

Kolejny trik można zrobić: Jeśli odkomentuj for -loop w getfunc widać, że inspect może dać ci „kontekst”, który naprawdę jest linia kodu źródłowego, gdzie funkcja został sprawdzony.Ten kod oczywiście nie pokazuje zawartości żadnej zmiennej przypisanej do twojej funkcji, ale czasami pomaga już znać nazwę zmiennej używanej jeden poziom powyżej twojej wywołanej funkcji.

Jak widać, dzięki dekoratorowi nie trzeba zmieniać kodu wewnątrz funkcji.

Prawdopodobnie będziesz chciał dość wydrukować argumenty. Pozostawiłem surowy wydruk (a także zakomentowaną instrukcję drukowania) w funkcji, dzięki czemu łatwiej się z nim bawić.

Powiązane problemy