0

Given a dictionary params={'a':0, 'b':1, 'c':2, 'd':3} I want to pass them to a function foo:

def foo(a, b, c=None, d=None):
   pass

Something as simple as foo(**params) would complain about mixing positional and named arguments.

There is an ugly way:

a = params['a']
b = params['b']
del params['a']
del params['b']
foo(a, b, **params)

But what I am ideally looking for is something like:

def separate(params:  Dict, func: Callable) -> List[Any], Dict[str, Any]:
   ...


args, kwargs = separate(params, foo)
foo(*args, **kwargs)

Is there a nice way to do it or should I rely on inspect and implement the separate function myself here?

[related questions don't address the issue: 1, 2]

y.selivonchyk
  • 8,987
  • 8
  • 54
  • 77

1 Answers1

1

Can you try this?

import inspect
from typing import Dict, Callable, List, Any

def separate(params: Dict, func: Callable) -> List[Any], Dict[str, Any]:
    sig = inspect.signature(func)
    args = []
    kwargs = {}
    for name, param in sig.parameters.items():
        if name in params:
            if param.kind == param.POSITIONAL_OR_KEYWORD:
                args.append(params[name])
            elif param.kind == param.KEYWORD_ONLY:
                kwargs[name] = params[name]
    return args, kwargs

If there is anything you can't understand from the code comment below!

Nova
  • 406
  • 2
  • 13