Search code examples
pythonpython-3.xkeyword-argument

How to pass kwargs with the same name as a positional argument of a function?


I am trying to call a wrapper from SK-learn which passes its **kwargs to an inner function. Unfortunately, one of its positional arguments has the same name as one of the arguments I want to pass in the **kwargs. I can't figure out how to pass them properly.

Example:

# This is a stand-in for a library function. I can't modify its behaviour.
def outer_function(fn, a, **kwargs):
    # do something entirely unrelated with a
    fn(**kwargs)

def expects_parameter_a(a):
    print(a)

def expects_parameter_b(b):
    print(b)

outer_function(expects_parameter_b, a=10, b=20) # this works as expected.
> 20

outer_function(expects_parameter_a, a=10, a=20) # this doesn't work.
outer_function(expects_parameter_a, a=10, kwargs={"a": 20}) # this doesn't work.
outer_function(expects_parameter_a, a=10, **{"a": 20}) # this doesn't work.

Solution

  • Don't make those parameters "first level" arguments; instead, accept a dict of arguments you're going to pass on to fn:

    def outer_function(fn, a, fn_kwargs):
        # do something entirely unrelated with a
        fn(**fn_kwargs)
    
    outer_function(expects_parameter_a, a=10, fn_kwargs={"a": 20})
    

    This could really be simplified and generalised to this:

    from functools import partial
    
    def outer_function(fn, a):
        ...
        fn()
    
    outer_function(partial(expects_parameter_a, a=20))
    # or:
    outer_function(lambda: expects_parameter_a(a=20))
    

    In other words, don't let outer_function worry about passing on the parameters at all, simply pass in a callable that already has all necessary parameters bound to it.