If and Comparisons

This page describes the if-statement, == comparisons, if-else and other related structures.

If Statement

The if-statement controls if some lines run or not.

The if-statement syntax has 4 parts (similar to "while"): if, boolean-test, colon, indented body lines:

if boolean-test:
  indented body lines

If Operation: Evaluate the boolean test, and if it is True, run the "body" lines once. Otherwise skip the body lines, and the run continues after the last body line.

The simplest and most common sort of boolean test uses == (two equal signs next to each other) to compare two values, and it's True if the two are the same.

Here is an example that shows an if-statement inside a for-loop. Every time through the loop, the test num == 6 is evaluated, yielding the boolean value True or False each time.

>>> for num in [2, 4, 6, 8]:
        if num == 6:
            print('Yay 6!')
Yay 6!

If test = vs. == Syntax Error

Note that it's very easy to accidentally type a single equal sign for a comparison like the following, but in Python that is flagged as a syntax error

if num = 6:       # typo, meant ==

Aside: in the language C, the above typo runs silently, interpreting the test as always True regardless of the value of i. Finding that tiny typo that can take many, many hours of debugging. The Python behavior is much better: when the == is not present, the line is flagged as an error.

Style: Do Not Write x == True

Suppose some foo() function is supposed to return True or False. Do not write an if-test like this:

if foo() == True:   # NO NO NO == True

Instead, let the if/while take the boolean value directly like this:

if foo():           # YES this way

# Or to test if foo() is False use not:
if not foo(): 
    print('not yay')

If Else

The optional else: part of an if-statement adds code to run in the case that the test is False. Use else if the run should do exactly one of action-1 or action-2 dependin gon the test (use regular if to do action-1 or nothing).

# set message according to score
if score > high_score:
    message = 'New high score!'
    message = 'Oh well!

The else clause is always about picking 1 of 2 actions. To run code if a test is False and otherwise do nothing, just use not like this:

if not foo():
    message = 'no foo today'

Boolean Comparison Operators

The most common way to get a boolean True/False is comparing two values, e.g. the comparison expression num == 6 evaluates to True when num is 6 and False otherwise.

Comparison operators:

==   test if two values are equal (2 equals signs together). Works for int, string, list, dict, .. most types. Not recommended to use with float values.

!=   not-equal, the opposite of equal (uses == under the hood)

< <=   less-than, less-or-equal. These work for most types that have an ordering: numbers, strings, dates. For strings, < provides alphabetic ordering. Uppercase letters are ordered before lowercase. It is generally an error to compare different types for less-than, e.g. this is an error: 4 < 'hello'

> >=   greater than, greater-or-equal.

The interpreter example below shows various == style comparisons, and for each what boolean value results:

>>> 5 == 6
>>> 5 == 5
>>> 5 != 6
>>> 4 > 2
>> 4 > 5
>>> 4 > 4
>>> 4 >= 4
>>> s = 'he' + 'llo'
>>> s == 'hello'
>>> 'apple' < 'banana'
>>> 'apple' < 4
TypeError: '<' not supported between instances of 'str' and 'int'

If Elif

There is a more rarely used elif for where a series of if-tests can be strung together (mnemonic: 'elif' is length 4, like 'else'):

if s == 'a':
    # a case
elif s == 'b':
    # b case
    # catch-all case

The tests are run top to bottom, running the code for the first that is True. However, the logic of when each case runs can be hard to see. What must be true for case c below? You really have to think about the code work work out when (c) happens.

if score > high and s != 'alice':
    # a
elif s == 'bob':
    # b
    # c

Answer: c happens when s is not 'bob' but also (score <= high or s == 'alice or both)

If/else chains are fine, just don't think they are trivial. Only add else if the code needs it. Nice, simple if handles most problems and is the most readable.

Return vs. if/else chains

Nick style idea: only use else when it is truly needed. If the code can work using only a plain-if, I prefer to write it that way. This works extra well with decomposed out functions, where 'return' can be used to bail out for the first few cases, leaving the main case below without indentation, like this:

def foo(s):
    if len(s) < 4:
        return 'too small!'

    if len(s) > 100:
        return 'too big!'

    # rest of computation having screened out too-short and too-long
    # notice: no if-else structure, not indented down here

You can use else if you prefer, just thinking about possible alternative structure here.

Python if - de-facto True/False

The Python if statement looks like this

if test:
    print('test is true!')

Surprisingly, any value can be used in the test expression - string, int, float, list, ...

Python has a de-facto True/False system, where all the "empty" values count as de-facto False: '', None, 0, 0.0, empty-list, empty-dict

Any other value de-facto counts as True: a non-empty string, a non-zero int, a non-empty list. Many languages use this anything-empty-is-false system. The bool() function takes any value and returns a formal bool False/True value, so that's a way to see the empty=False interpretation:

>>> bool(0)
>>> bool(0.0)
>>> bool('')   # empty string - False
>>> bool([])   # empty list - False
>>> bool(None)
>>> bool(6)       # non-zero int - True
>>> bool('hi')    # non-empty string - True
>>> bool([1, 2])  # list of something - True

Why does the de-facto system exist? It makes it easy to test, for example, for an empty string like the following. Testing for "empty" data is such a common case, it's nice to have a shorthand for it.

# long form screen out empty string
if len(s) > 0:

# shorter way, handy!
if s: