Это действительно сложно. Позвольте мне попытаться дать более полный ответ, повторно используя этот код , и подсказку о getargspec
в ответе Сентила, которая меня как-то сработала. Кстати, getargspec
устарела в Python 3.0, и вместо нее следует использовать getfullarcspec
. .
Это работает для меня на Python 3.1.2 как с явным вызовом функции отладки, так и с использованием декоратора:
# 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
Использование:
@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()
и отпечатки:
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
Декоратор немного обманывает: поскольку в wrapped
мы получаем те же аргументы, что и сама функция, не имеет значения, что мы находим и сообщаем ArgSpec wrapped
в getfunc
и debug_prt_func_args
. Этот код можно немного украсить, но теперь он работает хорошо для простых тестовых случаев отладки, которые я использовал.
Еще один трюк, который вы можете сделать: если вы раскомментируете for
-loop в getfunc
, вы можете увидеть, что inspect
может дать вам «контекст», который действительно является строкой исходного кода, где вызывается функция. Этот код, очевидно, не показывает содержимое какой-либо переменной, переданной вашей функции, но иногда он уже помогает узнать, какое имя переменной используется на один уровень выше вызываемой функции.
Как видите, с декоратором вам не нужно менять код внутри функции.
Вероятно, вы захотите напечатать аргументы. Я оставил в функции необработанный текст (а также закомментированный оператор печати), чтобы с ним было легче поиграться.