# Python informer

## 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
• Tertiary 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 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:


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:


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. In fact, 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. 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 respresent 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 alwys counts as False.

Any other objects that aren’t collections will normally count as True. This includes any types 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 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.

## Tertiary 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 make 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 advatange 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'):