1
def f(a=2, **b):
    print(a,b)

f(**{'a':3})

Why does this print 3 {} and not 2 {'a': 3}?

I can understand why it printed 3 {} if it was f(a=3) but I don't understand the output in this case.

wjandrea
  • 28,235
  • 9
  • 60
  • 81
user14095422
  • 79
  • 1
  • 7
  • 5
    because `f(**{'a': 3})` is equivalent to `f(a=3)` that is the point. any variables that aren't explicitly defined go to `b` and rest expand as expected. – Tadhg McDonald-Jensen Aug 12 '20 at 21:02
  • 4
    If it helps your understanding, try `f(a=4, **{'a': 3})` -> `TypeError: f() got multiple values for keyword argument 'a'` – wjandrea Aug 12 '20 at 21:10
  • BTW welcome to SO! Check out the [tour], and [ask] if you want advice. – wjandrea Aug 12 '20 at 21:11
  • 1
    @chris_rands I don't think that duplicate is appropriate. The question here is about sending a kwargs dict containing a kwarg that is already specified explicitly. It might not be obvious from just reading a question on using `**`. – Dan Aug 12 '20 at 21:16

2 Answers2

3

The unpacking operator, when used on a dict, passes the dict's contents as keyword arguments.

In other words, the following two lines are functionally identical:

f(a=3)
f(**{'a':3})

Since a is getting passed explicitly as a keyword argument, the default value of 2 is overwritten. And since no other arguments are passed, the **b argument is left empty.

Green Cloak Guy
  • 23,793
  • 4
  • 33
  • 53
1

The call f(**{'a':3}) is same as f(a=3), so the value of a is 3 and not the default 2. For b , using the unpacking operator **, it means to save all the other mapping variable into it, as there is no one, it values an empty dict

  • a is 3
  • b is empty dict, {}

So it prints 3 {}


To use b you need to pass argument named differently as a

# both print: 3 {'foo': 'bar', 'number': 100}
f(**{'a':3, 'foo':'bar', 'number':100}) 
f(a=3, foo='bar', number=100)
azro
  • 53,056
  • 7
  • 34
  • 70