416

In a similar way to using varargs in C or C++:

fn(a, b)
fn(a, b, c, d, ...)
Salvador Dali
  • 214,103
  • 147
  • 703
  • 753
David Sykes
  • 48,469
  • 17
  • 71
  • 80
  • 6
    I refer the honorable lottness to podcast 53: http://itc.conversationsnetwork.org/shows/detail4111.html?loomia_si=t0:a16:g2:r2:c0.246273:b24677090 – David Sykes May 28 '09 at 11:10
  • 3
    I gotta go with Mr Lott on this one. You can quickly get an authorative answer on this one in the Python docs, plus you'll get a feel for what else is there in the docs. It is to your benefit to get to know those docs if you plan on working in Python. – Brian Neal May 28 '09 at 19:41
  • @DavidSykes Link is broken – Dave Liu Jun 06 '19 at 18:06
  • The episode #53 "let's go Rio" cannot be the one mentioned by @DavidSykes in 2009, since it was recorded in 2013. Strangely, there was another #53 also recorded in 2011, also after David's comment: https://open.spotify.com/episode/3KVIJQoDDJWcAJzCjnKDio?si=4de4702aa3384761 – ouranos Mar 01 '23 at 09:22
  • @ouranos Could it be this #53? https://stackoverflow.blog/podcast/page/46/ – David Sykes Mar 02 '23 at 16:35

6 Answers6

529

Yes. You can use *args as a non-keyword argument. You will then be able to pass any number of arguments.

def manyArgs(*arg):
  print "I was called with", len(arg), "arguments:", arg

>>> manyArgs(1)
I was called with 1 arguments: (1,)
>>> manyArgs(1, 2, 3)
I was called with 3 arguments: (1, 2, 3)

As you can see, Python will unpack the arguments as a single tuple with all the arguments.

For keyword arguments you need to accept those as a separate actual argument, as shown in Skurmedel's answer.

Nicolas Gervais
  • 33,817
  • 13
  • 115
  • 143
unwind
  • 391,730
  • 64
  • 469
  • 606
  • 10
    Also important...one may find a time when they have to pass an unknown number of arguments to a function. In a case like this call your "manyArgs" by creating a list called "args" and passing that to manyArgs like this "manyArgs(*args)" – wilbbe01 Feb 16 '11 at 06:02
  • 4
    This is close, but this is unfortunately not general enough: `manyArgs(x = 3)` fails with `TypeError`. Skumedel's answer shows the solution to this. The key point is that the general signature of a function is `f(*list_args, **keyword_args)` (not `f(*list_args)`). – Eric O. Lebigot Mar 15 '13 at 03:36
  • 5
    The type of `args` is `tuple`. `kwargs` means **keyword args**. The type of `kwargs` is `dictionary`. – RoboAlex Feb 04 '19 at 07:36
  • 1
    Just `for arg in args:` for iterating through passed args – MasterControlProgram Sep 17 '19 at 13:48
  • I have to pass variable number of integer parameters followed by optional string, can I call use xxx(*arg: int, log: str = "") ? The variety in the number of parameters is small 0, 1, 2 or 3, so I can use overloads but it seems like it is not not available in python. – uuu777 Jan 01 '21 at 15:19
259

Adding to unwinds post:

You can send multiple key-value args too.

def myfunc(**kwargs):
    # kwargs is a dictionary.
    for k,v in kwargs.iteritems():
         print "%s = %s" % (k, v)

myfunc(abc=123, efh=456)
# abc = 123
# efh = 456

And you can mix the two:

def myfunc2(*args, **kwargs):
   for a in args:
       print a
   for k,v in kwargs.iteritems():
       print "%s = %s" % (k, v)

myfunc2(1, 2, 3, banan=123)
# 1
# 2
# 3
# banan = 123

They must be both declared and called in that order, that is the function signature needs to be *args, **kwargs, and called in that order.

Skurmedel
  • 21,515
  • 5
  • 53
  • 66
  • 2
    Not sure how you got myfunc(abc=123, def=456) to work, but in mine (2.7), 'def' can't be passed in this function without getting a SyntaxError. I assume this is because def has meaning in python. Try myfunc(abc=123,fgh=567) instead. (Otherwise, great answer and thanks for it!) – Dannid Aug 15 '13 at 20:46
  • @Dannid: No idea either haha... doesn't work on 2.6 or 3.2 either. I'll rename it. – Skurmedel Aug 16 '13 at 09:01
  • When you say 'called in that order', do you mean passed in that order? Or something else? – Nikhil Prabhu Sep 25 '16 at 16:17
  • 1
    @NikhilPrabhu: Yeah. Keyword arguments must come last when you call it. They always come last if you have non-keyword arguments in the call too. – Skurmedel Sep 26 '16 at 17:26
  • 6
    For Python 3: Just exchange `print a` with `print(a)`, and `kwargs.iteritems():` with `kwargs.items()`. – MasterControlProgram Sep 17 '19 at 13:51
28

If I may, Skurmedel's code is for python 2; to adapt it to python 3, change iteritems to items and add parenthesis to print. That could prevent beginners like me to bump into: AttributeError: 'dict' object has no attribute 'iteritems' and search elsewhere (e.g. Error “ 'dict' object has no attribute 'iteritems' ” when trying to use NetworkX's write_shp()) why this is happening.

def myfunc(**kwargs):
for k,v in kwargs.items():
   print("%s = %s" % (k, v))

myfunc(abc=123, efh=456)
# abc = 123
# efh = 456

and:

def myfunc2(*args, **kwargs):
   for a in args:
       print(a)
   for k,v in kwargs.items():
       print("%s = %s" % (k, v))

myfunc2(1, 2, 3, banan=123)
# 1
# 2
# 3
# banan = 123
wizzwizz4
  • 6,140
  • 2
  • 26
  • 62
calocedrus
  • 2,430
  • 20
  • 25
14

Adding to the other excellent posts.

Sometimes you don't want to specify the number of arguments and want to use keys for them (the compiler will complain if one argument passed in a dictionary is not used in the method).

def manyArgs1(args):
  print args.a, args.b #note args.c is not used here

def manyArgs2(args):
  print args.c #note args.b and .c are not used here

class Args: pass

args = Args()
args.a = 1
args.b = 2
args.c = 3

manyArgs1(args) #outputs 1 2
manyArgs2(args) #outputs 3

Then you can do things like

myfuns = [manyArgs1, manyArgs2]
for fun in myfuns:
  fun(args)
Vladtn
  • 2,506
  • 3
  • 27
  • 23
1
def f(dic):
    if 'a' in dic:
        print dic['a'],
        pass
    else: print 'None',

    if 'b' in dic:
        print dic['b'],
        pass
    else: print 'None',

    if 'c' in dic:
        print dic['c'],
        pass
    else: print 'None',
    print
    pass
f({})
f({'a':20,
   'c':30})
f({'a':20,
   'c':30,
   'b':'red'})
____________

the above code will output

None None None
20 None 30
20 red 30

This is as good as passing variable arguments by means of a dictionary

Rob
  • 4,927
  • 12
  • 49
  • 54
  • 3
    This is terrible code. Far better would be: `f = lambda **dic: ' '.join(dic.get(key, 'None') for key in 'abc')` – metaperture Dec 22 '16 at 20:35
1

Another way to go about it, besides the nice answers already mentioned, depends upon the fact that you can pass optional named arguments by position. For example,

def f(x,y=None):
    print(x)
    if y is not None:
        print(y)

Yields

In [11]: f(1,2)
1
2

In [12]: f(1)
1