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
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.
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)
.*
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 ...
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.
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.
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