The If Statement

The if statement is a compound statement and control flow tool that is used for conditional execution.

if_stmt ::= "if" assignment_expression ":" suite
            ("elif" assignment_expression ":" suite)*
            ["else" ":" suite]

Comparison Operators

Relational or Comparison Operators
Equality (Equal) a == b
Inequality (Not Equal) a != b
Greater than a > b
Greater than or equal to a >= b
Less than a < b
Less than or equal to a <= b

Equality

When people first attempt to pick up a programming language they usually notice a difference between testing for equality in mathematics and testing for equality in most programming languages. The equality operator in math is = while in Python and most programming languages it is ==.

x, y = 1000, 10

# testing two numbers for equality inside the condition of an if statement. The code block in the if statement is never reached because 1000 is not equal to 10.
if x == y:
    print(f"{x} is equal to {y}")

# in this second example, the code block is executed because 1000 is equal to 1000.
if x == 1000:
    print(f"{x} is equal to 1000")

'''
1000 is equal to 1000
'''

Inequality

There is one way we can get dissimilar values to execute. One such method is to use the != or “not equal” operator. unlike x == y above, x != y will execute the if statement’s code block because x is not equal to y, or 1000 is not equal to 10.

x, y = 1000, 10

# unlike x == y above, x != y will execute the if statement's code block because x is not equal to y, or 1000 is not equal to 10.
if x != y:
    print(f"{x} is not equal to {y}")

Greater Than & Lesser Than

We can also test a variable to see if it is greater than another number or variable.

x, y = 1000, 100

if x > y:
    print(f"{x} is greater than {y}")

This will of course not run because x is not less than y; however, this might be the intended effect. Perhaps, we do not wish it to run.

x, y = 1000, 100

if x < y:
    print(f"{x} is less than {y}")

… or equal to

We would use the >= and <= operators to achieve the exact same effect above, in addition to the inclusion of the endpoints being compared.

if 101 >= 100:
    print("101 is greater than or equal to 100")

if 100 <= 101:
    print("100 is less than or equal to 101")

Chained Comparisons

Comparisons can be chained arbitrarily. This could prove useful if you wanted to perform an operation on only a certain subset or range of an iteration.

if x < y and y <= z:
    pass

# equivalent to the above
# using the chained syntax
if x < y <= z:
    pass

If you haven’t gone through our fundamentals class on iteration please refer to for and while.

for i in range(10):
    if 0 <= i and i <= 3:
        print(i)
    else:
        print(None)

# using chained comparison
for i in range(10):
    if 0 <= i <= 3:
        print(i)
    else:
        print(None)
'''   
0
1
2
3
None
None
None
None
None
None
'''
# i is between -3 and 5 including the endpoints
for i in range(-3, 5+1):
    if 0 <= i <= 2:
        print(f"Index: {i:>2}, do something")
    else:
        print(f"Index: {i:>2}, ----------")

'''
Index: -3, ----------
Index: -2, ----------
Index: -1, ----------
Index:  0, do something
Index:  1, do something
Index:  2, do something
Index:  3, ----------
Index:  4, ----------
Index:  5, ----------
'''

The If-Elif-Else Chain

The if statement can also utilize optional elif (short for ‘else if’), and else clauses. The if statement selects exactly one suite by evaluating the expressions one by one until one is found to be true then that suite is executed. If all expressions are false, the suite of the else clause, if present, is executed.

x, y = 100, 5

# elif omitted
if x > y:
    print(f"It is true that {x} is greater than {y}")
else:
    print(f"{x} is not greater than {y}")

# else omitted
if x > y:
    print(f"It is true that {x} is greater than {y}")
elif x < y:
    print(f"It is true that {x} is less than {y}")

# if-elif-else chain
# else only on equality
if x > y:
    print(f"It is true that {x} is greater than {y}")
elif x < y:
    print(f"It is true that {x} is less than {y}")
else:
    print(f"{x} is neither greater than nor less than {y}")

# multiple elif clauses
if x > y:
    print(f"It is true that {x} is greater than {y}")
elif x < y:
    print(f"It is true that {x} is less than {y}")
elif x == y:
    print(f"{x} is equal to {y}")
else:
    print(f"never executed")

Logical Operators & Multiple Conditions

Logical Operators
Logical AND a and b
Logical OR a or b
Logical NOT not(a or b)
not a and not b

The logical AND operator can be implemented in the following ways within the if statement, each are identical, with the last example employing a Chained Comparison.

x = 7

# acceptable 0-9
if x >= 0 and x <= 9:
    pass

# acceptable 0-9
if 0 <= x and x <= 9:
    pass

# acceptable 0-9
if 0 <= x <= 9:
    pass

The Logical OR operator evaluates to true if either condition is met. The example below will run because x is greater than 3. If this had used AND the code would not have executed because both sides of the comparison would have had to evaluate to true.

x = 7

if x > 3 or x > 1000:
    print("condition met")

You can also invert or negate a condition with the logical NOT operator. The first example will not run because the condition is, of course, false. The second example inverts the false boolean into a true one.

false_condition = False

if false_condition:
    print("Never reached.")

if not false_condition:
    print("This will execute.")

Another good thing to understand is De Morgan’s theorem. This theorem states that the negation of an OR is the AND of the negations; and the negation of a AND is the OR of the negations.”

“the negation of a disjunction is the conjunction of the negations;
and the negation of a conjunction is the disjunction of the negations.”

( not True and not False ) == ( not (True or  False) )
( not True or  not False ) == ( not (True and False) )

Testing For Membership

Membership Operators
True if sequence a is in b a in b
True if sequence a is not in b a not in b

We can also use the if statement in conjunction with the membership operator and a list to check and see if a list contains a certain value. The all() built-in function has a similar function to chaining AND without the messy code. When combined with a list comprehension, we can really reduce our code down to a clean and succinct snippet.

felines  = ['cheetah', 'puma', 'jaguar', 'leopard', 'lion', 'lynx', 'tiger', 'balinese', 'maine coon']
domestic = ['balinese', 'maine coon']

# It is true that both domestic cats are in the felines list
# The result is: [True, True] 
[i in felines for i in domestic]

# It is not true that all felines are domestic and so only 2 are true
# [False, False, False, False, False, False, False, True, True]
[i in domestic for i in felines]

The following examples will return True and execute the code block underneath the if statement. The any() built-in is the analogous OR equivalent.

# If *all* domestic cats are felines return True
# Use all if you want every item to be True
if all([i in felines for i in domestic]):
    print("do something")

# If *any* domestic cats are felines return True
# Use any if you only care that at least one is True
if any([i in felines for i in domestic]):
    print("do something")

# If *any* felines are domestic cats return True
if any([i in domestic for i in felines]):
    print("do something")

The following examples will return False and not execute the code block underneath the if statement.

# not all felines are domestic, therefore False
if all([i in domestic for i in felines]):
    print("do something")

One way of visualizing what could be happening inside the all() built-in function is to make a function of our own. If you have not taken our course on function definitions you may want to do that before attempting to understand this. Only for demonstration purposes.

# If *all* domestic cats are felines return True
if all([i in felines for i in domestic]):
    print("do something")

# Iterating through all domestic cat breeds
# and testing their membership to felines
def all_true(domestic_x, felines_y):
    try:
        for d in domestic_x:
            assert d in felines_y, "False detected"
    except AssertionError as error:
        print(f"{error}: {d}")
        return False
    
    return True