Search code examples
pythondecoratordefault-value

Default arguments in a function when using decorators


I cannot really tell how to use *args and **kwargs when combined with decorators and default arguments. Let me give you a MWE.

def outer(f):
    def inner(*args, **kwargs):
        print("args:", args)
        print("kwargs:", kwargs)

    return inner

@outer
def simple(x, y):
    pass

Running the simple function passing arguments in a different format. So:

Running:

simple(10, 20)

args: (10, 20)
kwargs: {}

Running:

simple(x=10, y=20)

args: ()
kwargs: {'x': 10, 'y': 20}

Running:

simple(10, y=20)

args: (10,)
kwargs: {'y': 20}

All of these seem to be expected. What I cannot understand is if I define the simple function with a default value something like:

@outer
def simple(x, y=100):
    pass

If I then run simple(10) I would have expected the outcome to be:

args: (10,)
kwargs: {'y': 100}

but I get

args: (10,)
kwargs: {}

instead. Probably my understanding is not that good, so how could I achieve the expected result?


Solution

  • In this case **kwargs is not about the function signature, it's about how you called it. And your call

    simple(10)
    

    have only specified one positional argument.

    Decorator (wrapper) knows nothing about the function and its default arguments. It just passes the arguments it received further.

    simple(*(10,), **{})
    

    If you want to do some excercise and write decorator that is informed about the defaults of a function it is wrapping, I suggest to take a look at inspect.signature().