Advanced: Conditional Expressions and Lazy Evaluation

Welcome to the Week 2 Advanced Python Notebook. This notebook is designed for students who already have substantial experience with Python and feel confident working with both the Beginner and Intermediate material.

Your task today is to carefully read through the content and complete the exercises at the end. These exercises are more challenging and are intended to deepen your understanding of how Python handles data behind the scenes.

Important: This notebook is only recommended if you are already very confident with Python. Before beginning, you must have attempted at least \(4\) exercises from both the Beginner and Intermediate notebooks. If you have not done so, please return to those notebooks first, as the material here builds directly on the Beginner material and is substantially more complex than the Intermediate.

In this notebook, you will explore one-line if statements, conditional expressions and lazy evaluation. This will deepen your understanding of conditional logic and boolean operators in Python.

Work through the examples carefully, and take your time with the exercises. They are designed to stretch your understanding and prepare you for advanced applications of Python.

Table of Contents

Important: In this notebook, we will build on the concept of an if statement, exploring more complex behaviour and syntax. To follow this material, you must be familiar with if statements as described in the beginner notebook. If you are unsure of if statements, please return to the beginner notebook and work through this first!

Writing if Statements on One Line

In Python, the syntax of an if statement appears as follows:

Python actually allows the if statement above to be condensed to a single line, like so:

If the if statement contains multiple lines of code, we can combine them onto a single line using semicolons ;. For instance, the below code:

is equivalent to:

We can also place elif and else statements on a single line in a similar way. For instance, the below code:

can be converted to:

In general, this sort of syntax is frowned upon, as it isn’t very easy to read. Still, it’s worth pointing out here, since it’s often mistaken for the more readable conditional expression syntax covered in the next section.

Conditional Expressions

When you’re writing code, you’ll often want a variable to take on one value in some situations and a different value in others. A straightforward way to do this is with an ifelse statement, like this:

However, the above code is quite verbose for quite a simple operation. Sometimes, it is more convenient to represent conditional definitions of this form using a conditional expression.

Here the conditional expression consists of everything following the equals symbol. The general syntax for a conditional expression is:

<expr1> if <conditional_expr> else <expr2>

When you run this, the <conditional_expr> expression in the center is evaluated first. If <conditional_expr> is evaluated as True then <expr1> is evaluated. Otherwise, <expr2> is evaluated.

Note that this means it is possible that one of <expr1> or <expr2> are never evaluated. For instance, in the below code the first expression should give a division by zero, but because it is never evaluated, no error is thrown.

Test your understanding: How could you modify the above code to throw a division by zero error?

We can incorporate conditional expressions into larger expressions using round brackets (). For instance, the below code computes \(x+|x|\) for an input x.

Test your understanding: Can you think of a way to compute result in the above using a single conditional expression, without adding x?

Lazy Evaluation

A conditional expression is a good example of lazy evaluation. In general, an evaluation is called lazy if only the values that are actually needed are computed. For instance, in the example from the previous section, the expression 1/0 was never evaluated - it was skipped entirely as it wasn’t needed - which is what makes the evaluation lazy.

The and and or operations we met last week are actually examples of lazy operations. We’ve already seen them used with Booleans, but in Python they can be applied to many other data types as well. Let’s start with a few quick examples:

In the first line, both operands are Booleans, so the result is False. But in the later examples, the result is not a Boolean - it’s one of the operands themselves. For instance, 5 and 10 returns 10, while 0 and 99 returns 0. To explain what’s going on here, lets consider what happens when x and y are Booleans and we compute x and y.

If we were computing x and y by hand, we would naturally start by looking at x. If x is False, then the whole expression must also be False - because in an and both sides need to be true. There’s no reason to even check y; we can just return the value of x (that is, False).

If, on the other hand, x is True, then the overall result depends entirely on y. In that case, x and y is true if and only if y is true.

So a simple way to describe the evaluation of x and y is:

  • If x is False, return x.
  • If x is True, return y.

The same evaluation rules apply even when the operands are numbers, strings, or other kinds of objects. To make this work, Python treats every value as either truthy or falsy when it’s used in a logical expression:

  • Falsy values behave like False. These include False itself, numeric zero (0, 0.0, etc.), the empty string "", empty containers like [] or {}, and None.

  • Truthy values behave like True. Almost everything else falls into this category: non-zero numbers, non-empty strings, non-empty lists, and so on.

You can check whether a variable is Truthy or Falsy by casting it too a Boolean. For example:

Exercises

Question 1: Below are two variables x and y. Use a conditional expression to compute the maximum of x and y.

Question 2: Without running code, describe what you think would happen if you ran each of the following lines of code:

  • my_variable = True and 1/0
  • my_variable = False and 1/0
  • my_variable = str(False and 1/0)
  • my_variable = str(False) and 1/0

Explain your answers.

Question 3: The below code prints the statement “This code is printed if my boolean is True.” if my_boolean is True, but doesn’t print anything otherwise. Explain why.

Question 4: Based on your answer to Question 2, use the and and or operators to write code which prints "A" if my_boolean is True and "B" otherwise. Do not use if statements for this question.

Question 5: In the section on Lazy Evaluation, we explained how the and operator evaluates Truthy and Falsy values by examining one variable at a time. Specifically, we saw that the expression x and y follows this rule:

  • If x is Falsy, return x.

  • If x is Truthy, return y.

Using the same line of reasoning, derive the corresponding rule for the or operator. Write code in the box below to test your result.