Reputation: 2424
I have a function that is responsible for getting data from the kwargs
of several other functions.
The other functions pass their own kwargs to this function along with a keep
argument that determines whether or not to keep these properties in the kwargs - i.e. whether to use get
or pop
.
def _handle_kwargs(keep, **kwargs):
# keep: whether to keep the kwarg when we're done with it (i.e. get or pop)
if keep: func = getattr(kwargs, 'get')
else: func = getattr(kwargs, 'pop')
# get or pop some kwargs individually
debug = func('debug', False)
assert isinstance(debug, bool)
...
# repeated for several different possible kwargs
return debug, some_other_kwarg, ...
def normal_function(**kwargs)
debug, some_other_kwarg = _handle_kwargs(False, **kwargs)
Getting the values from the kwargs works fine. However, if I try to pop
the kwargs, then they are still present in the original function's kwargs
. I suspect this is because _handle_kwargs
is only modifying its own kwargs.
How can I ensure that the kwargs are removed if I use pop
, even if that's coming from another function?
Upvotes: 1
Views: 794
Reputation: 13510
The problem is that you don't pass a dictionary to _handle_kwargs
. The **kwargs syntax when calling a function actually "explodes" kwargs.
That is, if kwargs is {'a':1, 'b':2}, then _handle_kwargs(False, **kwargs)
is equivalent to _handle_kwargs(False, kwargs['a'], kwargs['b'])
. You don't pass the kwargs
dict at all!
_handle_kwargs
collects them into a new dictionary, so it won't affect the original one.
The solution is very simple.
First, def _handle_kwargs(keep, kwargs):
without asterisks. Just receive a dict.
Second, call it like so:
def normal_function(**kwargs)
debug, some_other_kwarg = _handle_kwargs(False, kwargs)
See the second line - calling _handle_kwargs
without asterisks - just pass the dict.
Upvotes: 1
Reputation: 3817
I doubt you can do that passing to **kwargs, as it appears to be passed by value, but if it's ok to modify the inner function, you could pass kwargs as a plain dictionary, i.e. without the **
.
def test(x):
print(x)
x.pop('test')
print(x)
def real(**kwargs):
test(kwargs)
print(kwargs)
real(test='nothing', real='something')
Output
{'test': 'nothing', 'real': 'something'}
{'real': 'something'}
{'real': 'something'}
Upvotes: 2