Search notes:

Python: Function parameters

def F(foo, bar, baz)
    …
def F(foo, bar=42, baz='Hello world'):
    …
def F(foo, bar=42, **kwargs):
    …
def F(foo, bar, /)
def F(foo, bar, /, …, *)
def F(foo, bar, /, …, *, …)

Parameters vs arguments

The Python FAQ outlines a distinction between parameters and arguments:
The parameters are the names while the arguments are the actual values that are passed to the function.
The names and values of the parameters/arguments are stored in a function's symbol table.

Categories of parameters

A parameter falls in one of the following five categories
Positional or keyword The default category
Positional only Parameters that are defined on the left side of the slash parameter (/)
Keyword only Parameters that are defined on the right side of the asterisk parameter (*)
Var positional At most one that is defined with a asterisk (*paramName)
Var keyword At most one that is defined with two asterisks (**paramName)
Keyword arguments are named.
when calling a function, the names of the keyword arguments are separated from the argument values by an equal sign (=):
F(param_one = 42, param_two = 'hello World')
Positional arguments are not named.
When calling a function, the values of positional arguments are just stated by themselves, separated by a comma. (Hence, they're positional):
F(42, 'hello World')
Positional arguments must precede keyword arguments.
Positional arguments can also be passed from an iterable by prepending it with a * which expands the elements of the iterable to the passed parameters:
F(*iterable)
Keyword arguements can also be passed from a dict whose key-names correspond to the parameter-names. The dictionary is prepended by two asterisks (**):
F(**vals)

Passing (mutable) objects

The following example tries to demonstrate that objects are passed by reference.
Although an object is passed by reference, it is not possible to return a different object by the parameter. However, if the passed argument is a mutable object, the contents of the object can be modifed so that the caller sees the modifications.
def F(p):
  #
  # p refers to the same object that was passed
  # when F was called:
  #
    print('id(p) = {}'.format(id(p)))

  # Create a new object and let p refer
  # to the new object. This has no effect
  # on the reference that was passed to F:
  #
    p=[11,22,33]

  #
  # Another id will be printed:
  #
    print('id(p) = {}'.format(id(p)))

# -------------------------------------

def G(q):
    print('id(q) = {}'.format(id(q)))
  #
  # No new object is created, thus
  # the caller will see the changed
  # values:
  #
    q[0] = 11
    q[1] = 22
    q[2] = 33

  #
  # Same id is printed as before:
  #
    print('id(q) = {}'.format(id(q)))

# -------------------------------------

V = [1, 2, 3]
print('id(V) = {}'.format(id(V)))

F(V)
for v in V:
    print(v) # prints 1, 2 and 3

G(V)
for v in V:
    print(v) # prints 11, 22, 33
Github repository about-Python, path: /functions/parameters/passing-objects.py

Default argument values

Function parameters can be given default argument values. The values are used if the parameters are not explicitly given a value when the function is called:
def F(par, num = 42, txt='Hello world'):
    print('par = {}'.format(par))
    print('num = {}'.format(num))
    print('txt = {}'.format(txt))
    print('')

F('foo')
#
# par = foo
# num = 42
# txt = Hello world

F('bar', 99)
#
# par = bar
# num = 99
# txt = Hello world

F('baz',  3, 'good bye')
#
# par = baz
# num = 3
# txt = good bye

F('baz',  txt='abcdef')
#
# par = baz
# num = 42
# txt = abcdef
Github repository about-Python, path: /functions/parameters/default-argument-values.py
The values that are bound to an argument are determined when the function is defined, not when it is called.
N = 'baz'
L = ['foo','bar']

def F(val = N, lst = L):
    lst.append(val)

N = 'xyz'

#
#  The following call appends 'baz', not 'xyz' to L:
#
F()

print(L)
#
# ['foo', 'bar', 'baz']

F('abc')
print(L)
#
# ['foo', 'bar', 'baz', 'abc'] 

anotherList = ['a', 'b', 'c']
F(val = 'd', lst = anotherList)

print(L)
#
# ['foo', 'bar', 'baz', 'abc']

print(anotherList)
#
#  ['a', 'b', 'c', 'd']
Github repository about-Python, path: /functions/parameters/default-argument-values-bind.py

Variable number of positional and named arguments

A variable number of positional arguments («variadic arguments») is indicated by *posArgs. In this case, posArgs is a tuple that contains the respective values.
A variable number of named arguments is indicated by **namedArgs. In this case, namedArgs is a dict that contains the respective parameter/argument pairs.
def F(par_1, par_2, *posArgs, **namedArgs):

    print('par_1 : ', par_1)
    print('par_2 : ', par_2)

    for posArg in posArgs:
        print('posArg: ', posArg)

    for parName, argVal in namedArgs.items():
        print('{:6s}:  {}'.format(parName, argVal))

    print('')

F( 42, 'hello World')
F( 99, 'ninety-nine', 'foo', 'bar', 'baz')
F('A', 'B'          ,  x = 'eggs', y = 'why')
F('C', 'D'          , 'E', 'F', ltr = 'G')
Github repository about-Python, path: /functions/parameters/varnum.py

Unpacking arguments

A tuple (or also list) can be unpacked («exploded») by prefixing it with a single asterisk (*) when a function is called.
Similarly, a dict can be unpacked by prefixing it with two asterisks (**):
def F(par_1, par_2, par_3, par_4, par_5):

    print('par_1:', par_1)
    print('par_2:', par_2)
    print('par_3:', par_3)
    print('par_4:', par_4)
    print('par_5:', par_5)
    print('')


tup = 'T1', 'T2'
dct = {'par_4': 'D4',
       'par_5': 'D5',
       'par_3': 'D3'}

lst = [ 'L3', 'L4', 'L5' ]

F(*tup, **dct)
F(*tup,  *lst)
Github repository about-Python, path: /functions/parameters/unpack.py
See also unpacking iteratables with a *.

Slashes and asterisks as parameter name

If a parameter is a slash (/), it signifies that the parameters on its left side are position-only and hence cannot be called by name.
If a parameter is a asterisk (*), it signifies that the parameters between the / and the * may be positional or keyword parameters.
The parameters following the * are keyword-only parameters.
An example of a function with a / is divmod:
help(divmod)
…
divmod(x, y, /)
…

Parameter annotations

A parameter can be annotated with an expression:
def F(par : 'some annotation'):
    …
See more on that here.

Assigning arguments with values from a list comprehension

It is possible to assign values to arguments that are created by a list comprehension.
In the following example, the list that is created by the list comprehension is unpacked so that each argument is assigned the corresponding value.
def F(p1, p2, p3, p4, p5):
    
    print(f'p1 = {p1}, p2 = {p2}, p3 = {p3}, p4 = {p4}, p5 = {p5}')

F( *( (x ** 2)+3 for x in range(5) ) )
Github repository about-Python, path: /functions/parameters/list-comprehension.py

Index