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.

A flowchart showing if/elif/else: two diamond decision tests with their bodies, falling through to a final else body when both tests are false.

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.