XClose

An introduction to research programming with Python

Home
Menu

Using functions

Functions in Python (and other programming languages) are modular units of code which specify a set of instructions to perform when the function is called in code. Functions may take one or more input values as arguments and may return an output value. Functions can also have side-effects such as printing information to a display.

Calling functions in Python

Python provides a range of useful built-in functions for performing common tasks. For example the len function returns the length of a sequence object (such as a string) passed as input argument. To call a function in Python we write the name of the function followed by a pair of parentheses (), with any arguments to the function being put inside the parentheses:

In [1]:
len("pneumonoultramicroscopicsilicovolcanoconiosis")
Out[1]:
45

If a function can accept more than one argument they are separated by commas. For example the built-in max function when passed a pair of numeric arguments returns the larger value from the pair:

In [2]:
max(1, 5)
Out[2]:
5

Another built-in function which we have already seen several times is print. Unlike len and max, print does not have an explicit return value as its purpose is to print a string representation of the argument(s) to a text display such as the output area of a notebook code cell. For functions like print which do not have an explicit return value, the special null value None we encountered previously will be used as the value of a call to the function if used in an expression or assigned to a variable:

In [3]:
return_value = print("Hello")
print(return_value)
Hello
None

Function calls can be placed anywhere we can use a literal value or a variable name, for example

In [4]:
name = "Jim"
len(name) * 8
Out[4]:
24
In [5]:
total_length = len("Mike") + len("Bob")
print(total_length)
7

Getting help on functions

The built-in help function, when passed a function, prints documentation for the function, which typically includes a description of the what arguments can be passed and what the function returns. For example

In [6]:
help(max)
Help on built-in function max in module builtins:

max(...)
    max(iterable, *[, default=obj, key=func]) -> value
    max(arg1, arg2, *args, *[, key=func]) -> value
    
    With a single iterable argument, return its biggest item. The
    default keyword-only argument specifies an object to return if
    the provided iterable is empty.
    With two or more arguments, return the largest argument.

In Jupyter notebooks an alternative way of displaying the documentation for a function is to write the function names followed by a question mark character ?

In [7]:
max?

Positional and keyword arguments and default values

There are two ways of passing arguments to function in Python. In the examples so far the function arguments have only been identified by the position they appear in the argument list of the function. An alternative is to use named or keyword arguments, by prefixing some or all of the arguments with the argument name followed by an equals sign. For example, there is a built-in function round which rounds decimal numbers to a specified precision. Using the help function we can read the documentation for round to check what arguments it accepts

In [8]:
help(round)
Help on built-in function round in module builtins:

round(number, ndigits=None)
    Round a number to a given precision in decimal digits.
    
    The return value is an integer if ndigits is omitted or None.  Otherwise
    the return value has the same type as the number.  ndigits may be negative.

We see that round accepts two arguments, a number argument which specifies the number to round and a ndigits argument which specifies the number of decimal digits to round to. One way to call round is by passing positional arguments in the order specified in function signature round(number, ndigits=None) with the first argument corresponding to number and the second ndigits. For example

In [9]:
pi = 3.14159265359
round(pi, 2)
Out[9]:
3.14

To be more expicit about which parameters of the function the arguments we are passing correspond to, we can instead however pass the arguments by name (as keyword arguments)

In [10]:
round(number=pi, ndigits=2)
Out[10]:
3.14

We can in-fact mix and match position and keyword arguments, providing that all keyword arguments come after any positional arguments

In [11]:
round(pi, ndigits=2)
Out[11]:
3.14
In [12]:
round(number=pi, 2)
  Cell In [12], line 1
    round(number=pi, 2)
                     ^
SyntaxError: positional argument follows keyword argument

Unlike positional arguments the ordering of keyword arguments does not matter so for example the following is also valid and equivalent to the calls above

In [13]:
round(ndigits=2, number=pi)
Out[13]:
3.14

In the documentation for round we see that the second argument in the function signature is written ndigits=None. This indicates that ndigits is an optional argument which takes the default value None if it is not specified. The documentation further states that

The return value is an integer if ndigits is omitted or None

which indicates that when ndigits is left as its default value (that is the argument is omitted or explicitly set to None) the round function returns the value of number rounded to the nearest integer. The following are all equivalent therefore

In [14]:
round(pi)
Out[14]:
3
In [15]:
round(number=pi)
Out[15]:
3
In [16]:
round(number=pi, ndigits=None)
Out[16]:
3

Functions are objects

A powerful feature of Python (and one that can take a little while to wrap your head around) is that functions are just a particular type of object and so can be for example assigned to variables or passed as arguments to other functions. We have in fact already seen examples of this when using the help function, with a function passed as the (only) argument to help. We can also assign functions to variables

In [17]:
my_print = print
my_print
Out[17]:
<function print>
In [18]:
help(my_print)
Help on built-in function print in module builtins:

print(...)
    print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
    
    Prints the values to a stream, or to sys.stdout by default.
    Optional keyword arguments:
    file:  a file-like object (stream); defaults to the current sys.stdout.
    sep:   string inserted between values, default a space.
    end:   string appended after the last value, default a newline.
    flush: whether to forcibly flush the stream.

In [19]:
my_print("Hello")
Hello

While giving function aliases like this may not seem particularly useful at the moment, we will see that the ability to pass functions to other functions and assign functions to variables can be very useful in certain contexts.