2012-03-30 7 views
5

Unter Umständen möchte ich Debug-Stil Ausgabe wie folgt drucken:Drucken Namen von Variablen an eine Funktion übergeben

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

Ich möchte die debug Funktion folgendes drucken:

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

Ich denke, es sollte möglich sein, indem Sie das Modul inspect verwenden, um den Stack-Frame zu lokalisieren, dann die entsprechende Zeile zu finden, den Quellcode in dieser Zeile nachzuschlagen und die Namen der Argumente von dort abzurufen. Der Funktionsname kann durch Verschieben eines Stapelrahmens erhalten werden. (Die Werte der Argumente sind leicht zu erhalten: Sie werden direkt an die Funktion debug übergeben.)

Bin ich auf dem richtigen Weg? Gibt es irgendein Rezept, auf das ich mich beziehen kann?

Antwort

3

Sie etwas entlang der folgenden Zeilen tun könnte:

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() 

Dies gibt:

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

Das ist schön und einfach! Aber ich würde mehr Komplexität nicht stören, wenn es bedeutet, dass ich nicht jeden Variablennamen zweimal wiederholen muss: einmal als Schlüsselwort-Arg-Name und einmal als Schlüsselwort-Argumentwert. – max

+0

Sie könnten versuchen, 'debug (** locals())' aufzurufen. –

1

Sie sind es in der Regel richtig zu machen, obwohl es wäre einfacher, AOP für diese Art zu verwenden, von Aufgaben. Im Grunde, anstatt jedes Mal mit jeder Variable "debuggen" zu rufen, könnte man den Code mit Aspekten ausstatten, die gewisse Dinge bei bestimmten Ereignissen tun, wie beim Eingeben der Funktion zum Drucken von übergebenen Variablen und ihrem Namen.

Bitte beziehen Sie sich auf this Website und alt so post für weitere Informationen.

1

Ja, Sie sind in der richtigen Spur. Vielleicht möchten Sie sich inspect.getargspec anschauen, die ein benanntes Tupel von Argumenten, Varargs, Schlüsselwörtern und Standardwerten zurückgibt, die an die Funktion übergeben wurden.

import inspect 

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


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

Das ist wirklich schwierig. Lassen Sie mich versuchen und eine umfassendere Antwort geben this code, und den Hinweis über getargspec in Senthil Antwort, die mich irgendwie ausgelöst hat. Btw, getargspec ist in Python 3.0 und getfullarcspec should be used veraltet.

Dies funktioniert für mich auf einem Python 3.1.2 sowohl mit explizit die Debug-Funktion aufrufen und mit einem Dekorateur mit:

# 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 

Verbrauch:

@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() 

und Drucke:

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 

Der Dekorateur betrügt ein bisschen: Seit wrapped bekommen wir das gleiche a rguments als Funktion selbst ist es egal, dass wir die ArgSpec von wrapped in getfunc und debug_prt_func_args finden und melden. Dieser Code könnte ein wenig verschönert werden, aber es funktioniert jetzt gut für die einfachen Debug-Testfälle, die ich benutzt habe.

Ein weiterer Trick, den Sie tun können: Wenn Sie die for -loop in getfunc Kommentar- können Sie sehen, dass inspect können Sie den „Kontext“ geben, die wirklich die Zeile des Quellcodes ist, wo eine Funktion aufgerufen wurde.Dieser Code zeigt offensichtlich nicht den Inhalt einer Variablen an, die Ihrer Funktion zugewiesen wird, aber manchmal hilft es bereits, den Variablennamen zu kennen, der eine Ebene über Ihrer aufgerufenen Funktion verwendet wird.

Wie Sie sehen können, müssen Sie mit dem Dekorator den Code in der Funktion nicht ändern.

Wahrscheinlich werden Sie die Args schön drucken wollen. Ich habe den Raw-Print (und auch eine auskommentierte Print-Anweisung) in der Funktion gelassen, damit es einfacher ist, mit ihm herumzuspielen.

Verwandte Themen