Decorators get the decorated args?

Hi,

in

def f1(aFunc):
	def DecoratedWrapper(*args,**kwargs):
		print(kwargs)
		val = aFunc(*args,**kwargs)
		print('Finished','\n')
		return val

	return DecoratedWrapper

@f1
def f(a,b=9):
	print(a,b)

@f1
def add(x,y):
	return x + y


f('Hello')

print(add(5,3))

The line 3 print(kwargs) print nothing !?
who can I get the args and kwargs of the decorated function within DecoratedWrapper ?

Thanks.

What you passed were positional arguments, not keyword. If you want them to be passed as keyword arguments, you would write it like this:

print(add(a=5, b=3))
2 Likes

You passed your arguments as positional, not keyword:

In [3]: f('Hello')
   ...: 
   ...: print(add(5,3))
{}
Hello 9
Finished 

{}
Finished 

8

If you pass as keyword args:

In [4]: f(a='Hello')
   ...: 
   ...: print(add(x=5,y=3))
{'a': 'Hello'}
Hello 9
Finished 

{'x': 5, 'y': 3}
Finished 

8

You could write some code with inspect.signature to convert args and kwargs into a dict of parameters-to-values as if you got only kwargs, but it won’t happen by itself.

1 Like

Thanks !! :woman_facepalming:

and why when I’m doing

def f1(aFunc):
	def DecoratedWrapper(**kwargs):
		print(kwargs)
		val = aFunc(**kwargs)
		print('Finished','\n')
		return val

	return DecoratedWrapper

@f1
def f(a='Vaneloppe'):
	print(a)

f()

I got

{}
Vaneloppe
Finished

why the line 3 give me an empty dict ?
but line 4 the aFunc took it…

You have a default parameter a for f. What’s happening is:

def f(a='Vaneloppe'):
    print(a)

_f = f  # Keeping a reference around
f = f1(f)  # f = f1.DecoratedWrapper where aFunc == _f

Then when you call f(), DecoratedWrapper() is called with no arguments, so print(kwargs) prints {}. Then _f() is called. Because it has a default argument for a, print(a) prints that default.

It might help to add a little audit function that can show you the current function and the variables available to it:

import inspect

def audit():
    calling_frame = inspect.currentframe().f_back
    print(f'DBG: {calling_frame.f_code.co_name}: {calling_frame.f_locals}')

Then you drop this in your functions so you can see when and how each is called:

In [14]: def f1(aFunc):
    ...:     audit()
    ...:     def DecoratedWrapper(**kwargs):
    ...:         audit()
    ...:         print(kwargs)
    ...:         val = aFunc(**kwargs)
    ...:         print('Finished','\n')
    ...:         return val
    ...:     return DecoratedWrapper
    ...: 
    ...: @f1
    ...: def f(a='Vaneloppe'):
    ...:     audit()
    ...:     print(a)
    ...: 
DBG: f1: {'aFunc': <function f at 0x7889d8793e20>}

In [15]: f()
DBG: DecoratedWrapper: {'kwargs': {}, 'aFunc': <function f at 0x7889d8793e20>}
{}
DBG: f: {'a': 'Vaneloppe'}
Vaneloppe
Finished 

f1() is called during function definition, then when you call f(), you call DecoratedWrapper and then your original f() function.

1 Like

Thank you @effigies ,

The

import inspect

def audit():
    calling_frame = inspect.currentframe().f_back
    print(f'DBG: {calling_frame.f_code.co_name}: {calling_frame.f_locals}')

Was really useful !..

1 Like

Hi,

a good way to remember:

args   --> arguments

kwargs --> keyword arguments

that is, k = key, and w = word