Programming logic

By Martin McBride, 2018-07-24
Tags: logical operator de morgan's law truthy value nested if statements ternary if statement and or not precedence
Categories: python language beginning python


Introduction

In this lesson we will take a deeper look at programming logic and if statements, including:

  • Logical operators
  • De Morgan's law
  • Truthy values
  • Nested if statements
  • Ternary if statements

Logical operators

Sometimes you might need to take more than one factor into account when you write an if statement. We use and and or operators to do this.

The and operator

Suppose we wanted to make lemonade. You need lemons, of course, but that isn't all. You need sugar too. It isn't enough to just have sugar or lemons, you need both.

Here is how we test that there are enough lemons and sugar:

lemons = 12
sugar_kg = 3

if lemons >= 10 and sugar_kg >= 2:
    print("Let's make lemonade")

The code checks the number of lemons, and the amount of sugar, using the same type of comparison operators we have used before. The and operator ensures that the if block only runs if both conditions are true.

The or operator

The or operator combines two comparisons and gives a true result if either (or both) values are true. Here is an example:

day = 'monday'

if day == 'monday' or day == 'thursday':
    print("It's bath night!")

In this case, the message will be printed if the day is Monday or Thursday.

The not operator

Sometimes you need to check if something is not true. The not operator can do this. It inverts the sense of the test, swapping true and false. For example:

if x >=1 and not x > 10:
    print('a is between 1 and 10')

Of course, not x > 10 is identical to saying x <= 10, you can choose either if you think one is easier to understand. not is sometimes useful, for example with truthy values as we will see later in this tutorial.

Precedence

With an expression like this:

x = a*3 + b*2

we know, of course, that the multiplications are calculated first, and then the addition. That is because multiplication has higher precedence than addition. The same principle applies to logical expressions:

if lemons >= 10 and sugar_kg >= 2:
    print("Let's make lemonade")

The comparison operators have higher precedence, so they are calculated first before the and is evaluated. The program first checks that there are enough lemons, and if there are, it also checks if there is enough sugar - if both are true, the print statement is executed.

Python is quite clever. If there are not enough lemons, it knows the answer will be false (because and cannot be true if the first term is false), so it doesn't waste time checking the amount of sugar. This is a very useful feature, called short circuit evaluation.

Truthy values

Python has two special values, True and False that represent, as you would expect, true and false:

if True:
    print('This will always print')
if False:
    print('This will never print')

In addition, Python has certain other values that count as True or False. These are called truthy values. The rules are fairly simple.

Numbers

A numerical value counts as False if it is zero, True otherwise. So instead of this code:

x = 3
if x!=0:
    print('x is not zero')

You can write:

x = 3
if x:
    print('x is not zero')

Although this is optional, most Python programmers will naturally use the second method. When you get used to it, the first method will start to look a bit strange.

If you wanted to check if x is equal to 0, you can use not:

x = 0
if not x:
    print('x is zero')

Collections

A collection is any type of data structure that holds other values. An example we have met already is the list type. A string is also a collection (a collection of characters).

As you learn more Python you will meet tuples, dictionaries, sets, and maybe a few more types.

The general rule is that a collection counts as False if it is empty, True otherwise.

So for example you should never do this:

s = 'abc'
if len(s)!=0:
    print(s)

It is better to do this:

s = 'abc'
if s:
    print(s)

Others

Python has a special value None that can be used to represent no particular value. For example, if you want to create a variable but you don't yet know what its value should be, you can set it to None. In Python, None always counts as False.

Any other objects that aren't collections will normally count as True. This includes any types of object that you define yourself, unless you add code to change that behaviour.

Nested if statements

Sometimes it isn't possible to fit the logic into a single if statement. Sometimes they need to be nested.

Imagine a fairground ride has a minimum and maximum height restriction. You can't use the ride if you are less than 1.2m tall, or greater than 1.7m tall. We could check that with code like this:

print('How tall are you?')
height = float(input())
if height < 1.2:
    print('You are not tall enough to use this ride')
elif height > 1.7:
    print('You are too tall to use this ride')
else:
    print('You can use this ride')
print('done')

We might enhance this code. If someone enters their height as 1.15, then they are almost tall enough to ride. You might want to suggest that they come back next year (as well as telling them they cannot ride).

print('How tall are you?')
height = float(input())
if height < 1.2:
    print('You are not tall enough to use this ride')
    if height > 1.15:                             #1    
        print('Please come back next year')       #2
elif height < 1.7:
    print('You are too tall to use this ride')
else:
    print('You can use this ride')
print('done')

Notice that the new if statement (#1) is inside the block of the original if statement. It will only be called if the height is also less than 1.2, so it detects cases of the height between 1.15 and 1.2. Also, the print statement (#2) marks the end of both if statements, so the code indents move back 8 characters rather than just four.

In principle, you can nest if statement to depths of 3, 4, or whatever you need. But complex, nested if statements can be difficult to follow, and it is easy to make mistakes, which cause bugs. Later we will see how to create our own functions, which can help to make the code much easier to understand.

Ternary if statements

You will often find yourself writing code a bit like this:

if x < 0:
    s = 'negative'
else:
    s = 'positive'

The pattern here is that we are setting s to one value or the other depending on the value of x. Python provides a neat way of doing this:

s = 'negative' if x < 0 else 'positive':

You should generally consider using this, for several reasons:

  • It is more readable because the form of the code makes the intent clear - you are setting a single variable s to one value or another depending on x.
  • It is less error-prone. In the first form, you have to name s twice. You might accidentally type t the second time and introduce a bug.
  • It is shorter.

Another more subtle advantage is that it is an expression. So you could avoid using the variable s altogether, for example, if you wanted to print the result:

print('negative' if x < 0 else 'positive'):

See also

If you found this article useful, you might be interested in the book NumPy Recipes or other books by the same author.

Join the PythonInformer Newsletter

Sign up using this form to receive an email when new content is added:

Popular tags

2d arrays abstract data type alignment and angle animation arc array arrays bar chart bar style behavioural pattern bezier curve built-in function callable object chain circle classes clipping close closure cmyk colour combinations comparison operator comprehension context context manager conversion count creational pattern data science data types decorator design pattern device space dictionary drawing duck typing efficiency ellipse else encryption enumerate fill filter font font style for loop formula function function composition function plot functools game development generativepy tutorial generator geometry gif global variable gradient greyscale higher order function hsl html image image processing imagesurface immutable object in operator index inner function input installing iter iterable iterator itertools join l system lambda function latex len lerp line line plot line style linear gradient linspace list list comprehension logical operator lru_cache magic method mandelbrot mandelbrot set map marker style matplotlib monad mutability named parameter numeric python numpy object open operator optimisation optional parameter or pandas partial application path pattern permutations pie chart pil pillow polygon pong positional parameter print product programming paradigms programming techniques pure function python standard library radial gradient range recipes rectangle recursion reduce regular polygon repeat rgb rotation roundrect scaling scatter plot scipy sector segment sequence setup shape singleton slice slicing sound spirograph sprite square str stream string stroke structural pattern subpath symmetric encryption template tex text text metrics tinkerbell fractal transform translation transparency triangle truthy value tuple turtle unpacking user space vectorisation webserver website while loop zip zip_longest