Reputation: 381
Why does {'kwargs':{'1':'a', '2':'b'}}
appear when I run test_func()
?
I would have expected just this to print: {'1':'a', '2':'b'}
.
Code:
class MyClass:
def __init__(self, **kwargs):
self.kwargs = kwargs
def test_func(self):
print(self.kwargs)
test_kwargs = {'1':'a', '2':'b'}
my_class = MyClass(kwargs=test_kwargs)
my_class.test_func()
Ouput:
{'kwargs': {'1': 'a', '2': 'b'}}
Upvotes: 4
Views: 477
Reputation: 881783
It's because **kwargs
automagically collects the remaining (unused) named arguments and puts them in a dictionary for you, much the same as *args
collects the unused unnamed (positional) arguments into a tuple(a).
It's meant to handle things like:
my_class = MyClass(a=1, b=2)
which is possibly what you were trying to do.
The way you've done it in the question will result in a dictionary with the key kwargs
referencing the dictionary because it will create a single dictionary keyed on the argument name kwargs
- that is exactly what you see.
(a) You can see this behaviour in the following transcript:
Python 3.9.0 (default, Oct 12 2020, 02:44:01)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> def fn(one, two, *args, **kwargs):
... print(one)
... print(two)
... print(args)
... print(kwargs)
...
>>> fn(1, 2, 3, 4, 5, six=6, seven=7)
1
2
(3, 4, 5)
{'six': 6, 'seven': 7}
Keep in mind args
and kwargs
are conventions, not rules. You can use different names, it's the *
and **
that matter.
Upvotes: 2
Reputation: 83537
First, let's simplify your example. Since your question has nothing to do with classes, we can use a global function instead:
def test_kwargs(**kwargs):
print(kwargs)
Second, let's call this with a different name:
test_kwargs = {'1':'a', '2':'b'}
test_kwargs(test=test_kwargs)
Output:
{'test': {'1': 'a', '2': 'b'}}
Now we see that the name test
comes from the name given in the function call not the function definition. This is what happened in your original code.
Here are some other examples that might help clarify some things:
You can pass multiple arguments each with their own name:
test_kwargs(a=1, b=2)
Output:
{'a': 1, 'b': 2}
Or you can expand a dictionary as keyword arguments to a function:
test_kwargs(**test_kwargs)
Output:
{'1':'a', '2':'b'}
Upvotes: 0
Reputation: 8437
It's because you initialize the instance by passing 1 keyword argument named kwargs
with the dictionary as value.
If you want to see the dictionary as kwargs, you need to call in using my_class = MyClass(**test_kwargs)
Upvotes: 7