I want to make a function that being a decorator to another function will print that function call details - parameters names and effective values. My current implementation is this.
def describeFuncCall(func):
'''Decorator to print function call details - parameters names and effective values'''
def wrapper(*func_args, **func_kwargs):
print 'func_code.co_varnames =', func.func_code.co_varnames
print 'func_code.co_argcount =', func.func_code.co_argcount
print 'func_args =', func_args
print 'func_kwargs =', func_kwargs
params = []
for argNo in range(func.func_code.co_argcount):
argName = func.func_code.co_varnames[argNo]
argValue = func_args[argNo] if argNo < len(func_args) else func.func_defaults[argNo - func.func_code.co_argcount]
params.append((argName, argValue))
for argName, argValue in func_kwargs.items():
params.append((argName, argValue))
params = [ argName + ' = ' + repr(argValue) for argName, argValue in params]
print(func.__name__ + ' ( ' + ', '.join(params) + ' )')
return func(*func_args, **func_kwargs)
return wrapper
@describeFuncCall
def test(a, b = 4, c = 'blah-blah', *args, **kwargs):
pass
test(1)
#test(1, 3)
#test(1, d = 5)
test(1, 2, 3, 4, 5, d = 6, g = 12.9)
Kinda works, but with some bugs:
For call
test(1, 2, 3, 4, 5, d = 6, g = 12.9)
it prints
test ( a = 1, b = 2, c = 3, d = 6, g = 12.9 )
.
The expected result is
test ( a = 1, b = 2, c = 3, args = [4, 5], kwargs = {'d': 6, 'g': 12.9} )
I got stuck here. Can you help me to find the right solution?
@warvariuc's answer, upgraded to Python 3:
Its a bit old post but wanted to add my bit. Solution given by warvariuc does not work in all cases. If a method have default values as well as we send named arguments while calling, it does not give proper output. e.g. we get two values of b.
Adding my modified code.
Output
Here's how I solved it in Python 3, based on aliteralmind's answer, put more cleanly (PEP8) if I may say so. Majority of the inspiration for the cleanup came from the (currently) accepted answer by Robert King.
Code:
Output:
Note: The
wrapper
string in the output represents the function name of whatever makes thelogging.X()
message call.Example in use:
When I get the magical resources known as "time and energy", I'm interested in playing around with
LOG_FORMAT
, and figure out how I can replace thewrapper
substring with say filename and linenumber of function invocation =)Here is the updated version for Python 3.6+
Old version
Working version with default values:
Result:
Sorry its a bit messy. I modified some code from http://wiki.python.org/moin/PythonDecoratorLibrary#Easy_Dump_of_Function_Arguments
test(1, 2, 3, 4, 5, d = 6, g = 12.9)
output:
test ( a=1, b=2, c=3, args=[4, 5], kwargs={'d': 6, 'g': 12.9})