1

I have a function with some named parameters, and a dictionary that contains keys with those names, as well as some other keys. I want to call the function with values from the dictionary.

  • I can't use **data because Python will raise TypeError: unexpected keyword argument because of the extra keys.
  • The dict might not contain certain keys, so I can't reference the keys without checking that they exist (and I don't want to pass a default from get).
  • I can't rewrite the function because it is in a separate library.

How can I unpack only the keys that match the function parameters?

def do_something(arg1=None, arg2=''):
    ...

data = {'arg1': 1, 'arg2': 2, 'other': 3}

# doesn't work if key doesn't exist
do_something(arg1=data['arg1'], arg2=data['arg2'])

# too verbose, hard to extend
if 'arg1' in data:
    do_something(arg1=data['arg1'], arg2=data['arg2'])
else:
    do_something(arg2=data['arg2'])
davidism
  • 121,510
  • 29
  • 395
  • 339
Lee Netherton
  • 21,347
  • 12
  • 68
  • 102

2 Answers2

1

Just riffing here...

do_something(**{ k: data[k] for k in ['Arg1', 'Arg2'] if k in data })

That looks pretty nasty though.

joerick
  • 16,078
  • 4
  • 53
  • 57
1

Alternatively, I just dug this out of one of my projects

def call_with_optional_arguments(func, **kwargs):
    '''
    calls a function with the arguments **kwargs, but only those that the function defines.
    e.g.

    def fn(a, b):
        print a, b

    call_with_optional_arguments(fn, a=2, b=3, c=4)  # because fn doesn't accept `c`, it is discarded
    '''

    import inspect
    function_arg_names = inspect.getargspec(func).args

    for arg in kwargs.keys():
        if arg not in function_arg_names:
            del kwargs[arg]

    func(**kwargs)

In your case, it could be used like:

call_with_optional_arguments(do_something, **data)

--

(If you're wondering about the name, I used this to fire callback functions that the user of my library would pass in. 'optional' in this case means that func doesn't have to accept all the arguments I'm calling with)

joerick
  • 16,078
  • 4
  • 53
  • 57
  • thanks @joerick. I was hoping for some nice syntactical sugar, but it seems that there may not be any. I guess I could write a function to suite my needs. – Lee Netherton Jul 20 '16 at 16:05