0

So I was trying out the *args and **kwargs in Python. But I get an error that I cannot understand the reason of.

def new(a,b,c):
  print a,b,c

a={'a': 7, 'b': 8, 'c': 9}
b={'1':7, '2':8, '3':9}

new(**a)
new(**b)

The new(**a) prints the results as expected, that is, the keys, 7,8,9. But, new(**b) gives the error:

new(**b)
TypeError: new() got an unexpected keyword argument '1'

Could anyone explain this? I am passing string as an argument in both cases, but 'a' works and '1' doesn't.

Silencer310
  • 862
  • 2
  • 8
  • 25
  • Variables cannot be numbers, which means your dictionary keys should not start with one. – Nick Oct 06 '16 at 02:14
  • 2
    If you think about the fact that `new(**a)` is essentially `new(a=7, b=8, c=9)`, you can probably figure out why it does not work. – SethMMorton Oct 06 '16 at 02:15
  • @Nicarus There are two problems here. That is definitely one, but that's not what Python is choosing to raise as the error. – SethMMorton Oct 06 '16 at 02:16
  • 1
    The function you defined doesn't (and couldn't possibly) take arguments named `1`, `2`, or `3`. – user2357112 Oct 06 '16 at 02:25
  • Possible duplicate of [What does \*\* (double star) and \* (star) do for Python parameters?](http://stackoverflow.com/questions/36901/what-does-double-star-and-star-do-for-python-parameters) –  Oct 06 '16 at 04:11

3 Answers3

1

The reason is simple. When you pass a dictionary to a python function as kwargs it unpacks that and uses the keys in the dictionary as the names of the variables and you can **only use parameter names that you have specified in the function parameters list.

RFV
  • 831
  • 8
  • 22
  • 1
    I'd like to clarify that it is not just that the OP used numbers. This would have still failed if they tried to use the keys 'd', 'e', and 'f'. – SethMMorton Oct 06 '16 at 02:46
  • See my answer - you *can* have numeric `kwargs` –  Oct 06 '16 at 04:14
  • Actually @LegoStormtroopr, I am refering the **keys**, not the **values**. and the user did in fact not send number **keys** but stings of numbers. – RFV Oct 06 '16 at 04:19
0

for a dictionary data={"key1":val1, "key2":val2, ..., "keyn":valn} when you do dictionary unpacking in a function call, fun(**data), is equivalent to doing fun(key1=val1, key2=val2,..., keyn=valn) and this will success as long as your function had arguments key1,...,keyn and/or accept keyword arguments.

So the problem with new(**b) is that is trying to do new(1=7,2=8,3=9) which is a nonsense as the function only had arguments named a,b,and c, therefore the error.

For your, your second example try with list instead

b=[7,8,9]
new(*b)

Also, you may want to play around with this function

def test(*argv, **kwarg):
    print "positional arguments", argv
    print "key word arguments", kwarg

like for instance

test(1,23,42)
test(w=3,r="buu")
test(1,2,3,q=23,ans=42)
a=[143,56,76]
b={'a': 7, 'b': 8, 'c': 9}
test(*a,**b)
Copperfield
  • 8,131
  • 3
  • 23
  • 29
0

This is related to a similar question, but in short passing **kwargs to a method is a way to pass in a number of key word arguments as a dictionary.

The reason your attempt fails is that your method new defines 3 named arguments - a,b,c so if you pass in a kwargs dictionary it must have these values as keys.

Its important to note that you can also catch kwargs in the method so you can call a method with numeric arguments, like so:

def foo(**kwargs):
    print kwargs

a={'a': 7, 'b': 8, 'c': 9}
b={'1':7, '2':8, '3':9}

foo(**a)
foo(**b)

Gives:

{'a': 7, 'c': 9, 'b': 8}
{'1': 7, '3': 9, '2': 8}
Community
  • 1
  • 1