JAD
JAD

Reputation: 2170

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.

Upvotes: 1

Views: 2714

Answers (3)

anbocode
anbocode

Reputation: 73

You can try something like this

def f1(*args, **kwargs):
    print("args   : ", args)
    print("kwargs : ", kwargs)

f1()
f1(1, 2)
f1(a=100, b=200)
f1(1, a=100)
f1(1, 2, a=100, b=200)

Output...

args   :  ()
kwargs :  {}
args   :  (1, 2)
kwargs :  {}
args   :  ()
kwargs :  {'a': 100, 'b': 200}
args   :  (1,)
kwargs :  {'a': 100}
args   :  (1, 2)
kwargs :  {'a': 100, 'b': 200}

Upvotes: -2

MisterMiyagi
MisterMiyagi

Reputation: 50076

Pass the arguments to the inner function using functools.partial, and pass a to outer_function separately:

outer_function(partial(expects_parameter_b, b=20), a=10)
outer_function(partial(expects_parameter_a, a=10), a=20)

This avoids passing arguments from outer_function to the inner function, and thus circumvents any conflicts. Note that outer_function does not need to be modified for this to work.

Upvotes: 1

deceze
deceze

Reputation: 522005

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.

Upvotes: 1

Related Questions