Function groups related statements that are executed together to perform a specific task. To define a function,  we use the keyword 'def' followed by the name of the function and then parentheses that may include relevant parameters. 

ExampleEdit & Run
def add(a, b):
    print(f'{a} + {b} = {a + b}')

add(10, 20)
Output:
10 + 20 = 30[Finished in 0.010444958927109838s]

In the above example:

  • We defined a function called 'add'.
  • The function specifies two parameters i.e a and that should be replaced with actual arguments when the function is being called.
  • When calling the function 'add' we passed two arguments  10 and 20 to match the parameters a and b, respectively.

That is typically how arguments works in Python i.e the parameters are specified in the function's declarations, then the actual values are passed as arguments when the function is being called.

The difference between parameters and arguments

Sometimes, the terms 'parameter' and 'argument' are used interchangeably when dealing with functions. However, there is a clear distinction between the two which may not be very apparent.

The main difference between parameters and arguments is that parameters are used in function declaration while arguments are the actual values passed when the function is being called. The following diagram demonstrates this better:

parameters vs arguments in Python

Literarily speaking, parameters are simply placeholders for the values that will be passed as arguments when the function is called.

ExampleEdit & Run
def add(a, b):
    # a and b above are parameters
    print(f'{a} + {b} = {a + b}')

#20 and 30 below are passed as arguments for parameters a and b, respectively
add(20, 30)
Output:
20 + 30 = 50[Finished in 0.011015834985300899s]

Types of arguments

There are two type of arguments in Python i.e Positional Arguments  and  Keyword Arguments.

Positional arguments

Positional arguments are arguments passed to a function in a specific order, based on their position in the function call. 

ExampleEdit & Run

positional arguments example

def prod(a, b):
    print(f'{a} x {b} = {a + b}')

prod(3, 4)
Output:
3 x 4 = 7[Finished in 0.010347084142267704s]

Note that in the above example:

  • values 3 and 4 are passed as positional arguments when calling the function. 
  • The values are automatically assigned to parameters a and b depending on their posltion in the function call.
ExampleEdit & Run
def greater(a, b, c):
     print(max([a, b, c]))

greater(10, 3, 7)
Output:
10[Finished in 0.01116330293007195s]

Similarly, in the above example, argument 10 is assigned to parameter, 3 to parameter b and 7   to parameter c.

As you have noted above, in positional arguments, the order of the arguments is important as each arguments is assigned to the parameters that matches its posltion  i.e The first argument is assigned to the first parameter, the second argument to the second parameters and so on.

keyword arguments

Positional arguments, as we have demonstrated above, are passed to the function based on their position in the function call. On the other hand,  keyword arguments are passed to the function based on the argument's name. Each keyword argument is assigned to the parameter that  matches its name.

Consider the following example:

ExampleEdit & Run
def add(a, b):
    print(f'{a} + {b} = {a + b}')
    
add (a = 5, b = 7)
Output:
5 + 7 = 12[Finished in 0.009918370051309466s]

In the above example, we used keyword arguments when calling the function add(). Unlike in positional arguments, we are explicitly assigning an argument to a parameter through its name rather than  depending on its position. 

Since we are specifying explicitly what arguments should be matched to which parameter, the order of the arguments is not important.

ExampleEdit & Run
def add(a, b):
    print(f'{a} + {b} = {a + b}')
    
add (b = 7, a = 5)
Output:
5 + 7 = 12[Finished in 0.010040108114480972s]

positional and keyword arguments in same function call

Python allows positional arguments and keyword arguments to be used in the same function call. However, all positional arguments must come before the keyword arguments.

ExampleEdit & Run

positional and keyword arguments together

def add(a, b, c):
    '''get sum of three numbers'''
    print(f'{a} + {b} + {c} = { a + b + c}')

add(2, b = 3, c = 4)
Output:
2 + 3 + 4 = 9[Finished in 0.010046347975730896s]

Note that in the above example,

  • The value 2 is passed as a positional argument while values 3 and 4 are passed as keyword arguments.
  • The value 2 is automatically assigned to parameter while values 3 and 4 are manually assigned to parameters b and c , respectively.
ExampleEdit & Run
def prod(a, b, c):
    '''get product of 3 numbers'''
    print(f'{a} x {b} x {c} = {a * b * c}' )

prod(1, 2, c = 5)
Output:
1 x 2 x 5 = 10[Finished in 0.010720597114413977s]

It is worth noting that the positional arguments are passed to the first parameters and the keyword arguments can only be assigned to the remaining parameters. If  we assign a keyword argument to a parameter that has already been assigned to by  a positional argument, a TypeError will be raised.

ExampleEdit & Run
def add(a, b, c):
     print(f'{a} + {b} + {c} = {a + b + c}')

# a TypeError is raised
add(2, a = 3, b = 4)
Output:
Traceback (most recent call last):  File "<string>", line 5, in <module>TypeError: add() got multiple values for argument 'a'[Finished in 0.011167691089212894s]

In the above example, a TypeError exception is raised because we are trying to assign to a parameter a through a keyword argument and it has already been assigned to by the first positional argument.

Functions with default arguments

Sometimes we may  need to have defaults arguments such that ,  if a function is called without a certain argument, the function will use a default value. Python allows us to do this by assigning the default values to the respective parameters at the function's declaration. Consider the following example.

ExampleEdit & Run
def add(a, b = 10):
    print(f'{a} + {b} = {a + b}')

#using the default value
add(3)
#with the default value overriden.
add(3, 4)
Output:
3 + 10 = 133 + 4 = 7[Finished in 0.010150134097784758s]

In the above example we defined the function add() with two parameters a and b. The parameter b is given a default value of 10 so that if the value is not overridden when the function is being called, the default value is used.

Arbitrary number of arguments

Sometimes it not may not be known in advance how many arguments will be passed to a function. For example consider the case with the builtin print() function, the function can take an arbitrary number of positional arguments each representing a value to be printed to the console.

ExampleEdit & Run
print('a', 'b', 'c', 1, 2, 3, 4)
Output:
a b c 1 2 3 4[Finished in 0.009830542840063572s]

In the above example, we would have passed more or less values to be printed, the point is, the number of arguments that will be passed is not known in advance until the function is called. 

In the next parts we will understand how we can add such a functionality to custom/user-defined function.

Arbitrary positional arguments

To define a function that takes an arbitrary number of arguments, we use an asterisk (*)  before one of the function parameters.

ExampleEdit & Run
def add(*args):
    #args is a tuple
    print('args: ', args)
    print(sum(args))

add(10, 20, 30)
Output:
args:  (10, 20, 30)60[Finished in 0.0097934789955616s]

When a function defines a parameter that is preceded by a single asterisk,  it effectively supports variable number of positional arguments. By convention, this parameter is  usually named "args". The parameter should strictly be defined before all the non-default parameters.

ExampleEdit & Run
def add(a, b, *args ):
     print(a + b + sum(args))

add(10, 20, 30, 40)
Output:
100[Finished in 0.009706202894449234s]

In the above example, we defined two non-default positional parameters a and b before defining the parameter with the asterisk to represent any other parameters. You should always remember that the non-default positional parameters should always.

You should not that the arbitrary positional arguments are joined together into a tuple and you can access them just like  any other tuple. You can use a for loop to iterate through the tuple to access each item or you can use the index operator to access an individual item.

You cannot have more than one parameter defined with an asterisk, trying this will result in an an error being raised.

Arbitrary keyword arguments

Arbitrary keyword arguments are represented by a parameter that is preceded by two asterisks(**). All the arbitrary keyword arguments are combined into a dictionary with the parameter name as the dictionary key and the argument's value as the dictionary value.

ExampleEdit & Run
def add(**kwargs):
     print('kwargs: ', kwargs)
     print(sum(kwargs.values()))

add(a =10, b = 20, c = 30)
Output:
kwargs:  {'a': 10, 'b': 20, 'c': 30}60[Finished in 0.009955835994333029s]

Just like in positional arguments, you cannot have more than one parameter defined with double asterisks.

To summarize on this,  the following order should be followed when specifying parameters and arguments:

  1. Required Arguments/non-default arguments first
  2. Default Arguments second
  3. Variable-length positional arguments (*args) third
  4. Keyword Arguments (**kwargs) last