Search code examples
pythonnamed-parameters

Is there a neat (pythonic?) way to use named parameter defaults in Python given a condition?


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'])

Solution

  • 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)