CSci 150: Foundations of computer science
Home Syllabus Readings Projects Tests

More on if

elif clauses

We've already seen that an if statement can optionally have an else clause. It can also optionally have any number of elif clauses — an abbreviation for “else if” — preceding the else clause.

A classic application where elif is appropriate is in translating a score into a letter grade.

if score >= 90:
    grade = 'A'
elif score >= 80:
    grade = 'B'
elif score >= 70:
    grade = 'C'
elif score >= 60:
    grade = 'D'
else:
    grade = 'F'

The way this works is as follows: Upon encountering the if statement, the computer first checks the if statement's condition, and if it passes, it does the body of the if clause (“grade = 'A'”) and it is done with the whole statement. But if that condition fails, it proceeds to the next elif clause's condition; if that succeeds, it does that elif clause's condution and then is done with the whole statement. But if it fails too, it proceeds to the next elif clause's condition, going down until it finds the first condition that is met; or, if they all fail, doing the else clause's body (if it exists).

In this case, if score is 75, the first condition “score >= 90” fails, and then the second condition “score >= 80” fails, but the third condition “score >= 70” succeeds. So the body “grade = 'C'” is executed and we are done with the statement. While it happens to be true that the fourth condition “score >= 60” would also be successful, it is never even noticed, because the computer stops upon the first successful condition it finds.

Notice how the e's in elif and else all line up under the i in if. This is necessary for Python to recognize that they are all part of the same statement.

Boolean type

Just as “x + 4” is an expression — that is, some Python code that is evaluated to be a value — so is “x < 4”. In the case of “x < 4”, the resulting value is not a number but a value that is either true (if x is below 4) or false. Such a true/false value is called the Boolean type.

The Boolean type is most often used implicitly in programs, so that you don't even think about it. But it does occassionally show up explicitly. The following program — to see if all words in a sentence start with the letter p — is an example. Notice how it references True and False — Python's way of writing a true/false value directly into a program. (Oddly, True and False have to be capitalized.)

words = input().split()
all_ps = True
for w in words:
    if w[0] != 'p':
        all_ps = False
if all_ps:
    print('All words start with p')
else:
    print("Some words don't start with p")

To see this work, suppose the user types “peter piper picked a peck”.

w: peter piper picked a peck
all_ps: True False

It then reaches the final if statement. Notice that the if statement has simply “all_ps” as its condition. This is entirely legitimate, because the if is designed to take true/false values, and that is exactly what all_ps is. When the condition is true, we execute the if's body; and when it is false, we execute the else's body. In our example, all_ps ends up False, so the clause's body executes, displaying “Some words don't start with p”.

By the way, this program works very differently if we change the inner if to:

if w[0] != 'p':
    all_ps = False
else:
    all_ps = True

In this case, the final word (peck) would end up leading the else clause to be executed, which would set all_ps back to True. So the program would incorrectly display “All words start with p”.

Logic operators: and, or, not

Quite often we want to test multiple conditions on a line. We can combine two conditions together using the and operator. For example, suppose for some reason we want to test whether a variable num is both even and at least 100.

if num % 2 == 0 and num >= 100:
    print('Number is large and even')

Technically, and is an operator, like + or ==. In this case, though, and is built to take two Boolean values and produce a Boolean value in response. If both are true, the result is true.

We can also use the word or as an operator.

if num % 2 == 0 or num >= 100:
    print('Number is large or even')

In this case, we'll enter the if if num is even or if num is at least 100 — or if they both are. So 24, 167, and 102 would all lead to “Number is large or even” being displayed.

Like and, or is designed to deal with two Boolean values. To our English-speaking brains, the following makes perfect sense:

if num == 2 or 4:
    print('Number is 2 or 4')

But Python interprets this as “(num == 2or (4)” — that is, or is an operator whose precedence level is lower than ==, just as has a lower precedence than *. The second part — 4 — is true no matter what, so the value of the overall or is true regardless of num. So this little fragment always displays “Number is 2 or 4”, even if num is something completely different, like 37.

So how should we write this? We need to make sure “num ==” appears after or as well.

if num == 2 or num == 4:
    print('Number is 2 or 4')

Going to back to our even/large example, what if we somehow want to test whether a number is even or large, but not both? We can do this using the not operator, along with and and or.

if (num % 2 == 0 or num >= 100and not (num % 2 == 0 and num >= 100):
    print('Number is either large or even, but not both')

You'd want the parentheses here. Actually, Python does have an order of operations among the Boolean operators: not comes before and, which comes before or. But many experienced programmers prefer to add parentheses to make the order easier to understand. (In this case, the parentheses are actually required to get the order we want.)

Short-circuit logic operators

With and, Python will evaluate the first part first. If it turns out to be false, then there is no point in evaluating the second part, and so Python won't even bother. This is called short-circuit behavior.

Short-circuiting is often useful. For instance, suppose we want to test whether the third letter of a word is the letter z. Naturally, you might be tempted to write “if word[2] == 'z':” (remembering that slot 2 holds the third letter, since the slots are numbered starting from 0). However, when the word has only two letters, word[2] doesn't exist, and so Python would simply crash the program. The solution is to test whether the word has at least three letters before examining the third letter.

if len(word) >= 3 and word[2] == 'z':

If the word has only two letters, then the first condition will be false and so Python won't even bother with the second part — which is a good thing, because if it did, the program would crash. However, if the word does have three letters or more, it would go on to check the third letter.