2.11. Instrukcje warunkowe

Instrukcja warunkowa uruchamia blok kodu tylko wtedy, gdy jakiś test ma wartość prawdy. Słowem kluczowym jest if, opcjonalnie poprzedzające jedną lub więcej gałęzi elif („else if”) oraz końcowe else.

n = 42

if n > 0:
    print("positive")
elif n < 0:
    print("negative")
else:
    print("zero")

Ciałem każdej gałęzi jest wszystko, co jest wcięte pod nią (zgodnie z konwencją cztery spacje). Python przechodzi przez gałęzie w kolejności, uruchamia pierwszą, której test jest prawdziwy, i pomija pozostałe. Blok else uruchamia się tylko wtedy, gdy każdy poprzedzający test był fałszywy; jest zawsze opcjonalny.

Schemat blokowy przedstawiający if/elif/else: dwa romby decyzyjne z ich ciałami, przechodzące do końcowego ciała else, gdy oba testy są fałszywe.

Zawsze uruchamia się tylko jedna gałąź. Testy są wykonywane od góry do dołu, aż jeden się powiedzie; reszta jest pomijana.

2.11.1. Prawdziwość logiczna

Test w if nie musi zwracać True ani False – każda wartość liczy się jako prawdziwa lub fałszywa. Wartości fałszywe to:

  • False i None

  • Liczba zero: 0, 0.0

  • Puste sekwencje i kolekcje: "", [], (), {}, b""

Wszystko inne jest prawdziwe. Pozwala to pisać zwięzłe testy:

if name:                     # false on empty string
    print("hello", name)

if items:                    # false on empty list, dict, etc.
    process(items)

Pamiętaj, że prawdziwość logiczna zmienia znaczenie. if value: to nie to samo, co if value is not None: – pierwsze jest fałszywe również wtedy, gdy value wynosi 0 lub "". Gdy naprawdę masz na myśli „czy to dokładnie None”, użyj jawnie is None / is not None.

2.11.2. Wyrażenia warunkowe (ternarne)

Instrukcja warunkowa może pojawić się wewnątrz wyrażenia:

label = "even" if n % 2 == 0 else "odd"

Czytaj jako „label to "even" jeśli n % 2 == 0 w przeciwnym razie "odd"”. Przydatne dla jednowierszowców; dla czegokolwiek dłuższego niż jeden wiersz pełna instrukcja if jest łatwiejsza do odczytania.

2.11.3. Zagnieżdżanie i wczesne zwroty

Instrukcje warunkowe można zagnieżdżać dowolnie głęboko, ale każda dodatkowa warstwa wcięcia utrudnia odczytanie funkcji. Poniższy przykład sprawdza cztery warunki przed wykonaniem właściwej pracy i pozostawia użyteczny wiersz ukryty cztery wcięcia w głąb:

def process(item):
    if item is not None:
        if item.is_valid():
            if item.size() > 0:
                if item.owner == "me":
                    return do_the_work(item)
    return None

Dwa wzorce spłaszczają tego rodzaju kod.

2.11.3.1. Wczesne zwroty jako strażnicy

Obsłuż najpierw każdy przypadek „wyjścia”, każdy z własnym return, tak aby główna logika pozostała na zewnętrznym wcięciu. Każdy strażnik czyta się jako „to nie jest przypadek, który obsługujemy; wyjdź”:

def process(item):
    if item is None:
        return None
    if not item.is_valid():
        return None
    if item.size() == 0:
        return None
    if item.owner != "me":
        return None
    return do_the_work(item)

„Główna ścieżka” jest teraz jednym wierszem na dole funkcji, a nie ukryta wewnątrz czterech warstw. Ten styl bywa nazywany wzorcem klauzuli strażniczej.

2.11.3.2. Łączenie testów za pomocą and / or

Gdy kilka warunków musi być spełnionych jednocześnie dla tej samej gałęzi, połącz je za pomocą and zamiast zagnieżdżania. Warunki, z których każdy niezależnie wyzwala gałąź, łącz za pomocą or:

# all must hold -- use `and`
if user.is_admin() and user.has_permission("write") and not locked:
    save()

# any one of them is enough -- use `or`
if c == " " or c == "\t" or c == "\n":
    whitespace_count += 1

Obie postacie zwierają obwód, więc kosztowne sprawdzenie po prawej stronie uruchamia się tylko wtedy, gdy tańsze sprawdzenia po lewej jeszcze nie rozstrzygnęły kwestii.