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ć.
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
Możesz spróbować wywołać 'debug (** locals())'. –