What do *args and **kwargs mean? [duplicate]
Asked Answered
G

5

294

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?

Gonsalez answered 13/11, 2008 at 14:33 Comment(2)
Just a bad pun on Hours and Kilo-Watt Hours.Roede
This article can be very useful for understanding in depth the theme: agiliq.com/blog/2012/06/understanding-args-and-kwargsChartier
I
282

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.

Inexcusable answered 13/11, 2008 at 14:41 Comment(5)
No sweat, you’re very welcome. Confused me for a while as well. If you’re getting into Python seriously I’d heartily recommend ‘Programming Python’ by Mark Lutz.Inexcusable
Perhaps link to the tutorial which explains this in depth, and should be read by everyone: docs.python.org/tutorial/…Mcgray
@AliAfshar: Your link was all I needed, should've been the answer by itself. Thanks!Bouldon
@PaulD.Waite: No problem. I wonder how many rookies found this error by trying to use your code, but were telling themselves "I must be doing something wrong here, this answer has so many votes" ;) Another upvote from me, because it is very clear and very good.Fully
@Bouldon Link only answers are frowned upon, since the site they link to could vanish, leaving the answer useless for future visitors.Rowden
T
98

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.

Thorathoracic answered 13/11, 2008 at 15:44 Comment(3)
This is one of the most helpful answers I have found on how to use super. This answer is more than 5 years old, but I guess this is still a great way of using super in Python 2.X, correct?Livestock
Yes, still the way to do it.Baileybailie
Thanks, but it would be great if you could provide some real example ,why and when to use it. In the above example what happens if I don that that?Radioscope
F
75

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

Flytrap answered 13/11, 2008 at 17:23 Comment(3)
You can actually do also *mydict (not **mylist), but the result will be slightly different (and unexpected to some).Fully
simple, concise, and an easy to follow example to illustrate the point. My favorite kind of answer!Debouch
@Fully You can do *x for any iterable and **y for any mapping type. Since a dict is both an iterable and a mapping you can do either. See also #8601768Rubyeruch
F
26

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
Flytrap answered 13/11, 2008 at 17:31 Comment(0)
B
20

Just to clarify how to unpack the arguments, and take care of missing arguments etc.

def func(**keyword_args):
  #-->keyword_args is a dictionary
  print 'func:'
  print keyword_args
  if keyword_args.has_key('b'): print keyword_args['b']
  if keyword_args.has_key('c'): print keyword_args['c']

def func2(*positional_args):
  #-->positional_args is a tuple
  print 'func2:'
  print positional_args
  if len(positional_args) > 1:
    print positional_args[1]

def func3(*positional_args, **keyword_args):
  #It is an error to switch the order ie. def func3(**keyword_args, *positional_args):
  print 'func3:'
  print positional_args
  print keyword_args

func(a='apple',b='banana')
func(c='candle')
func2('apple','banana')#It is an error to do func2(a='apple',b='banana')
func3('apple','banana',a='apple',b='banana')
func3('apple',b='banana')#It is an error to do func3(b='banana','apple')
Butz answered 23/6, 2013 at 14:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.