\( \newcommand{\NOT}{\neg} \newcommand{\AND}{\wedge} \newcommand{\OR}{\vee} \newcommand{\XOR}{\oplus} \newcommand{\IMP}{\Rightarrow} \newcommand{\IFF}{\Leftrightarrow} \newcommand{\TRUE}{\text{True}\xspace} \newcommand{\FALSE}{\text{False}\xspace} \newcommand{\IN}{\,{\in}\,} \newcommand{\NOTIN}{\,{\notin}\,} \newcommand{\TO}{\rightarrow} \newcommand{\DIV}{\mid} \newcommand{\NDIV}{\nmid} \newcommand{\MOD}[1]{\pmod{#1}} \newcommand{\MODS}[1]{\ (\text{mod}\ #1)} \newcommand{\N}{\mathbb N} \newcommand{\Z}{\mathbb Z} \newcommand{\Q}{\mathbb Q} \newcommand{\R}{\mathbb R} \newcommand{\C}{\mathbb C} \newcommand{\cA}{\mathcal A} \newcommand{\cB}{\mathcal B} \newcommand{\cC}{\mathcal C} \newcommand{\cD}{\mathcal D} \newcommand{\cE}{\mathcal E} \newcommand{\cF}{\mathcal F} \newcommand{\cG}{\mathcal G} \newcommand{\cH}{\mathcal H} \newcommand{\cI}{\mathcal I} \newcommand{\cJ}{\mathcal J} \newcommand{\cL}{\mathcal L} \newcommand{\cK}{\mathcal K} \newcommand{\cN}{\mathcal N} \newcommand{\cO}{\mathcal O} \newcommand{\cP}{\mathcal P} \newcommand{\cQ}{\mathcal Q} \newcommand{\cS}{\mathcal S} \newcommand{\cT}{\mathcal T} \newcommand{\cV}{\mathcal V} \newcommand{\cW}{\mathcal W} \newcommand{\cZ}{\mathcal Z} \newcommand{\emp}{\emptyset} \newcommand{\bs}{\backslash} \newcommand{\floor}[1]{\left \lfloor #1 \right \rfloor} \newcommand{\ceil}[1]{\left \lceil #1 \right \rceil} \newcommand{\abs}[1]{\left | #1 \right |} \newcommand{\xspace}{} \newcommand{\proofheader}[1]{\underline{\textbf{#1}}} \)

2.1 Python’s Built-In Functions

In the previous chapter, we began our study of programming in Python by studying three main ingredients: literals, operators, and variables. We can express complex computations using just these forms of Python code, but as the tasks we want to perform grow more complex, so too does the code we need to write. In this chapter, we’ll learn about using functions in Python to organize our code into useful sections that can be written and updated independently and reused again and again across our programs.

Review: Functions in mathematics

Before looking at functions in Python, we’ll first review some of the mathematical definitions related to functions from the First-Year CS Summer Prep.

Let \(A\) and \(B\) be sets. A function \(f : A \to B\) is a mapping from elements in \(A\) to elements in \(B\). \(A\) is called the domain of the function, and \(B\) is called the codomain of the function.

Functions can have more than one input. For sets \(A_1, A_2, \dots, A_k\) and \(B\), a \(k\)-ary function \(f: A_1 \times A_2 \times \dots \times A_k \to B\) is a function that takes \(k\) arguments, where for each \(i\) between \(1\) and \(k\), the \(i\)-th argument of \(f\) must be an element of \(A_i\), and where \(f\) returns an element of \(B\). We have common English terms for small values of \(k\): unary, binary, and ternary functions take one, two, and three inputs, respectively. For example, the function \(f_1: \Z \to Z\) defined as \(f_1(x) = x^2 - 10\) is a unary function, and the function \(f_2: \R \times \R \times \R \to \R\) defined as \(f_2(x, y, z) = \frac{x}{y^2} + z\) is a ternary function.

We can call a mathematical function on a particular input (element of its domain), and calculate the corresponding output value by substituting the input value into the function definition and evaluating the expression. For example, using the functions \(f_1\) and \(f_2\) defined earlier,

\[ f_1(3) = (3)^2 - 10 = -1 \]

and

\[f_2(0.5, -1, 100) = \frac{0.5}{(-1)^2} + 100 = 100.5\]

Python’s built-in functions

We’ve seen that Python has many operators like + and in that can be used on various data types. These operators represent mathematical functions using special symbols (e.g., addition through the + symbol). But because these operators are written between two expressions, they are restricted to representing binary functions. So of course Python must have a way of representing functions beyond the operators we’ve studied so far.

Now, we’ll see some of Python’s built-in functions, which are functions that are made automatically available anywhere in a Python program. For example, Python has a built-in function named abs that takes a single numeric input and returns its absolute value. But just knowing this function exists isn’t enough—how do we actually use it?

A Python expression that uses a function to operate on a given input is called a function call, and has the same syntax as in mathematics:

<function>(<argument>, <argument>, ...)

Here are two examples of function call expressions that use abs:

>>> abs(-10)  # Returns the absolute value of -10.
10
>>> abs(100)
100

Function calls are central to programming, and come with some new terminology that we’ll introduce now and use throughout the next year.

Rounding numbers

Here is a second example of a numeric function, round. This one is a bit more complex than abs, and can be used in two different ways:

  1. Given a single argument number x, round(x) returns the int that equals x rounded to the nearest integer.

    >>> round(3.3)
    3
    >>> round(-1.678)
    -2
  2. Given an argument number x and a non-negative int d, round(x, d) returns the float value of x rounded to d decimal places.

    >>> round(3.456, 2)
    3.46
    >>> round(3.456, 0)  # This still returns a float
    3.0

More than numbers!

In your mathematical studies so far, you’ve mainly studied unary numeric functions, i.e., functions that take in just one numeric argument and return another number. Examples include the sin and log functions. In programming, however, it is very common to work with functions that operate on a wide variety of data types, and a wide number of arguments. Here are a few examples of built-in Python functions that go beyond taking a single numeric argument:

The type function

One additional useful built-in function is type, which takes any Python value and returns its data type. Let’s check it out: The term class that you see returned here is the word Python uses to mean “data type”. More on “classes” in later chapters.

>>> type(3)
<class 'int'>
>>> type(3.0)
<class 'float'>
>>> type(True)
<class 'bool'>
>>> type('David')
<class 'str'>
>>> type({1, 2, 3})
<class 'set'>
>>> type([1, 2, 3])
<class 'list'>
>>> type({'a': 1, 'b': 2})
<class 'dict'>

If you’re ever unsure about the data type of a particular value, you can always call type on it to check!

The help function:

The last special built-in Python function we’ll cover in this section is help, which takes a single argument and displays help documentation for that argument. help is most commonly used for finding out more about other functions: if we call help on a function, the Python interpreter will display information about how to use the function. You’ll find that the documentation for Python’s functions and data types contain terminology or concepts that you aren’t familiar with yet. That’s totally normal! Being able to read and make sense of programming language documentation is an essential skill for a computer scientist, and one that you will gain experience with throughout the year. If you ever encounter something in the Python help documentation that you don’t quite understand, please ask us about it!

>>> help(abs)
Help on built-in function abs in module builtins:

abs(x, /)
    Return the absolute value of the argument.

It is also possible to call help on individual values like 3 or {1, 2, 3}; doing so will display the documentation for the data type of that value, like int or set. We don’t recommend doing this for beginners, however, as the amount of documentation shown can be a bit overwhelming! Instead, we recommend using help for specific functions, at least when first starting out.

A note about nesting function calls

Just like other Python expressions, you can write function calls within each other, or mix them with other kinds of expressions like arithmetic expressions.

>>> max(abs(-100), 15, 3 * 20)
100
>>> sorted({10, 2, 3}) + sorted([-1, -2, -3])
[2, 3, 10, -3, -2, -1]

However, just as we saw with deeply nested arithmetic expressions earlier, too much nesting can make Python expressions difficult to read and understand. So, it is a good practice to break down a complex series of function calls into intermediate steps using variables:

>>> value1 = abs(-100)
>>> value2 = 15
>>> value3 = 3 * 20
>>>> max(value1, value2, value3)
100

References