Conditions

if operator

Python has one omnipotent logical condition check operator: if.

if <condition>:
    <actions_when_condition_is_True>
elif <another_optional_condition>:
    <actions_when_optional_condition_is_True>
else:
    <actions_when_conditions_are_False>

🪄 Code:

a = 12
if a > 10: 
    print("a is greater than 10" )
elif a == 3: 
    print("a is 3" )
elif a == 5:
    print("a is 5")
else: 
    print("a is lesser than 3")

📟 Output:

a is greater than 10

bool type

Boolean type is subclass of int. So for Python True is 1, False is 0.

Its only instances are False and True

The built-in function bool() can be used to convert any value to a Boolean, if the value can be interpreted as a truth value

🪄 Code:

True + True

📟 Output:

2

🪄 Code:

(True + True + True) * (True + True) - False

📟 Output:

6

🪄 Code:

bool(24), bool("sdsds"), bool(""), bool([])

📟 Output:

(True, True, False, False)

Truth Value Testing

Any object can be tested for truth value, for use in an if or while condition or as operand of the Boolean operations below. The following values are considered False:

  • None

  • False

  • zero of any numeric type, for example, 0, 0.0, 0j.

  • any empty iterable, for example, '', (), [], set(), frozenset().

  • any empty mapping, for example, {}.

  • instances of user-defined classes, if the class defines a __bool__() or __len__() method, when that method returns the integer zero or bool value False.

All other values are considered true — so objects of many types are always true.

Boolean operations

  • or

  • and

  • not

  • ^ (XOR - exclusive OR - only if its arguments differ)

OperationResult

x or y

if x is false, then y, else x

x and y

if x is false, then x, else y

not x

if x is false, then True, else False

Sometimes it can surprise you. The following example will always print the first quote:

🪄 Code:

decision = "not to be"
if decision == "be" or "to be":
    print("Take arms against a sea of troubles!")
else:
    print("You will not see this quote anyway =(")

📟 Output:

Take arms against a sea of troubles!

Because the expression is equivalent to:

(decision == "be") or ("to be")

Solution:

decision in ("be", "to be")

Precedence of operations in Python:

The following table summarizes the operator precedence in Python, from lowest precedence (least binding) to highest precedence (most binding). Operators in the same box have the same precedence. Unless the syntax is explicitly given, operators are binary. Operators in the same box group left to right (except for exponentiation, which groups from right to left).

OperatorDescription

lambda

Lambda expression

- if – else

Conditional expression

or, and, not x

Boolean OR, AND, NOT

in, not in, is, is not, <, <=, >, >=, !=, ==

Comparisons, including membership tests and identity tests

|, ^, &

Bitwise OR, XOR, AND

<<, >>

Shifts

+, -

Addition and subtraction

*, @, /, //, %

Multiplication, matrix multiplication, division, floor division, remainder

+x, -x, ~x

Positive, negative, bitwise NOT

**

Exponentiation

await x

Await expression

x[index], x[index:index], x(arguments...), x.attribute

Subscription, slicing, call, attribute reference

(expressions...), [expressions...], {key: value...}, {expressions...}

Binding or tuple display, list display, dictionary display, set display

Structural Pattern Matching

Sometimes it is pain to manage the tree-like structure of if-elif-elif-elif-else statements. It is becoming a burden to maintain:

if subject == value1:
    <action_1>
elif subject == value2:
    <action_2>
else:
    <default_action>

In Python 3.10 we got a completely new syntax for defining of a match statement and case statements of patterns with associated actions allowing substitute a mess of multiple elif conditions with a much clear structure.

The generic syntax of pattern matching is:

match subject:
    case <pattern_1>:
        <action_1>
    case <pattern_2>:
        <action_2>
    case _:
        <default_action>

Pattern matching will try each pattern until a match to run an action from it or the lastly defined default match action. The match is comparing the structure/value of the pattern and a given item. It is possible to substitute exact values in the pattern with variables and use them in a action.

An example:

🪄 Code:

def http_error(status):
    match status:
        case 400:
            return "Bad request"
        case 404:
            return "Not found"
        case 500 | 501 | 502:  # We can use set-like case pattern
            return "Server Error"
        case _:
            return "The status is not supported"

print(http_error(500))

📟 Output:

Server Error

We can even assign variables using patterns:

🪄 Code:

GOOD_MARKS = [4, 5]

def check_student(student: tuple) -> str:
    match student:
        case (name,):
            return f"No mark for student {name} passed"
        case ("", _):
            return f"Empty student name is not supported"
        case (_, 0):
            return f"Mark 0 is not supported"
        case (name, mark):
            return f"Student {name} has a {'good' if mark in GOOD_MARKS else 'bad'} mark"
        case _:
            return "Incorrect value passed - should be: (NAME: str, MARK:int)"

student1 = "John", 0
print(check_student(student1))

📟 Output:

Mark 0 is not supported

If we don't specify a second tuple item or pass None or any other object instead of a 1,2-item tuple:

🪄 Code:

print(check_student(("Steve",)))
print(check_student(None))
print(check_student((1, 2, 3)))

📟 Output:

No mark for student Steve passed
Incorrect value passed - should be: (NAME: str, MARK:int)
Incorrect value passed - should be: (NAME: str, MARK:int)

Last updated