3

I came across an error which I don't quite understand. If I have the following snippet:

class Test(object):
  def __init__(self):
    self.data = {}

  def update_data(self, **update):
    self.data = update

t = Test()

t.update_data(test='data') #  Works
t.update_data({'test':'data'}) #  TypeError: update_data() takes 1 positional argument but 2 were given

So from what I understand, the **update syntax is the dictionary destructing syntax and when you pass a dict to the function, it gets converted into keyword arguments.

What am I understanding improperly here?

2
  • 4
    You need to use it like: **{'test': 'data'} if you want to pass a dictionary
    – bergerg
    Commented Jul 31, 2017 at 12:27
  • 1
    I think this post would help you understand the whole concept. Commented Jul 31, 2017 at 12:29

2 Answers 2

9

If you just pass in a dictionary it will be treated as any other variable. In your case you passed it in as positional argument so it will be treated as positional argument. The method, however, doesn't accept any positional arguments (except self but that's another story) so it throws an error.

If you want to pass the dictionary contents as keyword arguments you need to unpack it (** in front of the dictionary):

t.update_data(**{'test':'data'})

If you want to pass in a dictionary as dictionary you can also pass it in as keyword argument (no unpacking is done then!):

t.update_data(funkw={'test':'data'})
1
  • 1
    Yup, that makes sense. Unpacking the dictionary would essentially turn it into a keyword argument, right? Which is what the method here is accepting.
    – Bhargav
    Commented Jul 31, 2017 at 12:59
2

When you pass keyword arguments to a function, it gets converted to a dictionary. Not the other way around.

Detail explanation of args and kwargs

*args means a function/method can accept any number of positional arguments and will be stored in a list called args.

**kwargs means it can accept any number of named arguments and will be stored in a dictionary called kwargs Still unclear? Let me give an example (albeit very simple and naive) -

# Suppose you want to write a function that can find the 
# sum of all the numbers passed to it.

def sum(a, b):
    return a + b

>>> sum(2, 3) # => 5

# Now this function can only find sum of two numbers, what 
# if we have 3, 4 or more numbers, how would be go solving that.
# Easy let's take an array/list as an argument -

def sum(numbers):
    total = 0

    for number in numbers:
        total += number

    return total

# But now we'd have to call it like -
>>> sum([2, 3]) # => 5
>>> sum(2, 3) # => throws an error.

# That might be ok for some other programming languages, but not 
# for Python. So python allows you to pass any number of 
# arguments, and it would automatically store them into list 
# called args (as a conventions, but it can be called 
# anything else say 'numbers')

def sum(*numbers):
    total = 0

    for number in numbers:
        total += number

    return total

>>> sum(2, 3, 4) # => 9

# Viola! 

Similarly kwargs are used to automatically store all named arguments as a dictionary.

1
  • this line=> sum([2, 3]) # => 5 solved everything for me
    – Akhil Jain
    Commented Jan 28, 2021 at 4:13

Not the answer you're looking for? Browse other questions tagged or ask your own question.