Python Language Functions Defining a function with an arbitrary number of arguments

30% OFF - 9th Anniversary discount on Entity Framework Extensions until December 15 with code: ZZZANNIVERSARY9

Example

Arbitrary number of positional arguments:

Defining a function capable of taking an arbitrary number of arguments can be done by prefixing one of the arguments with a *

def func(*args):
    # args will be a tuple containing all values that are passed in
    for i in args:
        print(i)

func(1, 2, 3)  # Calling it with 3 arguments
# Out: 1
#      2
#      3

list_of_arg_values = [1, 2, 3]
func(*list_of_arg_values)  # Calling it with list of values, * expands the list
# Out: 1
#      2
#      3 

func()  # Calling it without arguments
# No Output 

You can't provide a default for args, for example func(*args=[1, 2, 3]) will raise a syntax error (won't even compile).

You can't provide these by name when calling the function, for example func(*args=[1, 2, 3]) will raise a TypeError.

But if you already have your arguments in an array (or any other Iterable), you can invoke your function like this: func(*my_stuff).

These arguments (*args) can be accessed by index, for example args[0] will return the first argument

Arbitrary number of keyword arguments

You can take an arbitrary number of arguments with a name by defining an argument in the definition with two * in front of it:

def func(**kwargs):
    # kwargs will be a dictionary containing the names as keys and the values as values
    for name, value in kwargs.items():
        print(name, value)

func(value1=1, value2=2, value3=3)   # Calling it with 3 arguments
# Out: value1 1
#      value2 2
#      value3 3

func()                               # Calling it without arguments
# No Out put

my_dict = {'foo': 1, 'bar': 2}
func(**my_dict)                      # Calling it with a dictionary
# Out: foo 1
#      bar 2

You can't provide these without names, for example func(1, 2, 3) will raise a TypeError.

kwargs is a plain native python dictionary. For example, args['value1'] will give the value for argument value1. Be sure to check beforehand that there is such an argument or a KeyError will be raised.

Warning

You can mix these with other optional and required arguments but the order inside the definition matters.

The positional/keyword arguments come first. (Required arguments).
Then comes the arbitrary *arg arguments. (Optional).
Then keyword-only arguments come next. (Required).
Finally the arbitrary keyword **kwargs come. (Optional).

#       |-positional-|-optional-|---keyword-only--|-optional-|
def func(arg1, arg2=10 , *args, kwarg1, kwarg2=2, **kwargs):
     pass
  • arg1 must be given, otherwise a TypeError is raised. It can be given as positional (func(10)) or keyword argument (func(arg1=10)).
  • kwarg1 must also be given, but it can only be provided as keyword-argument: func(kwarg1=10).
  • arg2 and kwarg2 are optional. If the value is to be changed the same rules as for arg1 (either positional or keyword) and kwarg1 (only keyword) apply.
  • *args catches additional positional parameters. But note, that arg1 and arg2 must be provided as positional arguments to pass arguments to *args: func(1, 1, 1, 1).
  • **kwargs catches all additional keyword parameters. In this case any parameter that is not arg1, arg2, kwarg1 or kwarg2. For example: func(kwarg3=10).
  • In Python 3, you can use * alone to indicate that all subsequent arguments must be specified as keywords. For instance the math.isclose function in Python 3.5 and higher is defined using def math.isclose (a, b, *, rel_tol=1e-09, abs_tol=0.0), which means the first two arguments can be supplied positionally but the optional third and fourth parameters can only be supplied as keyword arguments.

Python 2.x doesn't support keyword-only parameters. This behavior can be emulated with kwargs:

def func(arg1, arg2=10, **kwargs):
    try:
        kwarg1 = kwargs.pop("kwarg1")
    except KeyError:
        raise TypeError("missing required keyword-only argument: 'kwarg1'")

    kwarg2 = kwargs.pop("kwarg2", 2)
    # function body ...

Note on Naming

The convention of naming optional positional arguments args and optional keyword arguments kwargs is just a convention you can use any names you like but it is useful to follow the convention so that others know what you are doing, or even yourself later so please do.

Note on Uniqueness

Any function can be defined with none or one *args and none or one **kwargs but not with more than one of each. Also *args must be the last positional argument and **kwargs must be the last parameter. Attempting to use more than one of either will result in a Syntax Error exception.

Note on Nesting Functions with Optional Arguments

It is possible to nest such functions and the usual convention is to remove the items that the code has already handled but if you are passing down the parameters you need to pass optional positional args with a * prefix and optional keyword args with a ** prefix, otherwise args with be passed as a list or tuple and kwargs as a single dictionary. e.g.:

def fn(**kwargs):
    print(kwargs)
    f1(**kwargs)

def f1(**kwargs):
    print(len(kwargs))

fn(a=1, b=2)
# Out:
# {'a': 1, 'b': 2}
# 2


Got any Python Language Question?