What do *args and **kwargs mean?

Viewed 168541

What exactly do *args and **kwargs mean?

According to the Python documentation, from what it seems, it passes in a tuple of arguments.

def foo(hello, *args):
    print(hello)

    for each in args:
        print(each)

if __name__ == '__main__':
    foo("LOVE", ["lol", "lololol"])

This prints out:

LOVE
['lol', 'lololol']

How do you effectively use them?

5 Answers

Putting *args and/or **kwargs as the last items in your function definition’s argument list allows that function to accept an arbitrary number of arguments and/or keyword arguments.

For example, if you wanted to write a function that returned the sum of all its arguments, no matter how many you supply, you could write it like this:

def my_sum(*args):
    return sum(args)

It’s probably more commonly used in object-oriented programming, when you’re overriding a function, and want to call the original function with whatever arguments the user passes in.

You don’t actually have to call them args and kwargs, that’s just a convention. It’s the * and ** that do the magic.

The official Python documentation has a more in-depth look.

Also, we use them for managing inheritance.

class Super( object ):
   def __init__( self, this, that ):
       self.this = this
       self.that = that

class Sub( Super ):
   def __init__( self, myStuff, *args, **kw ):
       super( Sub, self ).__init__( *args, **kw )
       self.myStuff= myStuff

x= Super( 2.7, 3.1 )
y= Sub( "green", 7, 6 )

This way Sub doesn't really know (or care) what the superclass initialization is. Should you realize that you need to change the superclass, you can fix things without having to sweat the details in each subclass.

Notice the cool thing in S.Lott's comment - you can also call functions with *mylist and **mydict to unpack positional and keyword arguments:

def foo(a, b, c, d):
  print a, b, c, d

l = [0, 1]
d = {"d":3, "c":2}

foo(*l, **d)

Will print: 0 1 2 3

Another good use for *args and **kwargs: you can define generic "catch all" functions, which is great for decorators where you return such a wrapper instead of the original function.

An example with a trivial caching decorator:

import pickle, functools
def cache(f):
  _cache = {}
  def wrapper(*args, **kwargs):
    key = pickle.dumps((args, kwargs))
    if key not in _cache:
      _cache[key] = f(*args, **kwargs) # call the wrapped function, save in cache
    return _cache[key] # read value from cache
  functools.update_wrapper(wrapper, f) # update wrapper's metadata
  return wrapper

import time
@cache
def foo(n):
  time.sleep(2)
  return n*2

foo(10) # first call with parameter 10, sleeps
foo(10) # returns immediately
Related