Hello, world! 👋🏼
Being a Python developer since quite a few years now, this language still doesn't stop to teach me!
The other day I was refactoring a function that took just kwargs
as a parameter. We wanted to make functions more readable, so we thought of having few important entries from kwargs
as positional arguments.
So this:
def foo(**kwargs):
print(kwargs)
turned into this:
def foo(status, **kwargs):
print(kwargs)
Of course this requires that kwargs
should have the status
key, otherwise it would throw an error
TypeError: foo() missing 1 required positional argument: 'status'
After making this sure, things looked pretty readable; until a test case failed:
KeyError: 'status'
Wait. What? How?? I just changed the arguments, not a single line of code change inside the function..?
And yet, I got KeyError
for kwargs['status']
At first, this seemed as if it should not have had happened. But then, it did! Going back to the REPL and trying out few things quickly shed light onto a thing that I didn't know about kwargs
till that day.
Consider the below code:
>>> d = {'a': 'A', 'b': 'B'}
>>>
>>> def foo(x, **kwargs):
... print(x, kwargs)
...
>>> def bar(x, c, **kwargs):
... print(x, c, kwargs)
...
>>>
Now let's see what happens when we call these functions:
>>> foo(1, **d)
1 {'a': 'A', 'b': 'B'}
>>>
>>> bar(1, **d)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: bar() missing 1 required positional argument: 'c'
>>>
This error is the same as mentioned above. We solve this by making sure the key is present in the dict
:
>>> d['c'] = 'C'
>>>
And call the function again:
>>> bar(1, **d)
1 C {'a': 'A', 'b': 'B'}
>>>
Notice what happens when we print kwargs
- the key that we accepted as a positional argument (c
) got popped out of kwargs
! It was no more part of kwargs
, which explains why we got the KeyError
above - because before refactoring, the key status
was a part of kwargs
, which, after refactoring, was coming in as an individual argument and was no more a part of kwargs
.
It's a small thing, but can go unnoticed. Thanks to test cases, we were saved from creating another incident report..
Top comments (1)
On a side note:
kwargs
dict has to be the name of the positional argument. So, ifstatus
is supposed to be the positional argument, thenkwargs
is expected to have the same key