2.11. Feltételes utasítások

Egy feltételes utasítás csak akkor futtat le egy kódblokkot, ha valamilyen teszt igazra értékelődik ki. A kulcsszó az if, amelyet opcionálisan egy vagy több elif („else if”) ág és egy záró else követhet.

n = 42

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

Az egyes ágak törzse minden, ami alá behúzással kerül (megegyezés szerint négy szóköz). A Python sorrendben végigjárja az ágakat, lefuttatja az elsőt, amelynek a tesztje igaz, a többit pedig kihagyja. Az else blokk csak akkor fut le, ha minden megelőző teszt hamis volt; ez mindig opcionális.

Egy folyamatábra, amely az if/elif/else szerkezetet mutatja: két rombusz alakú döntési teszt a törzsükkel, amelyek egy záró else törzsbe esnek át, amikor mindkét teszt hamis.

Mindig csak egyetlen ág fut le. A tesztek fentről lefelé értékelődnek ki, amíg az egyik sikeres nem lesz; a többit a rendszer kihagyja.

2.11.1. Igazságérték

Egy if tesztjének nem kell True vagy False értéket visszaadnia – bármilyen érték igaz értékűnek (truthy) vagy hamis értékűnek (falsy) számít. A hamis értékű értékek a következők:

  • False és None

  • A nulla szám: 0, 0.0

  • Üres sorozatok és gyűjtemények: "", [], (), {}, b""

Minden más igaz értékű. Ez lehetővé teszi tömör tesztek írását:

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

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

Vedd figyelembe, hogy az igazságérték megváltoztatja a jelentést. Az if value: nem ugyanaz, mint az if value is not None: – az első akkor is hamis, amikor a value értéke 0 vagy "". Amikor valóban azt érted, hogy „pontosan None ez”, használd kifejezetten az is None / is not None formát.

2.11.2. Ternáris kifejezések

Egy feltételes utasítás megjelenhet egy kifejezésen belül is:

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

Így olvasandó: „a label értéke "even" ha n % 2 == 0 különben "odd"„. Kényelmes egysorosokhoz; bármi, ami egy sornál hosszabb, könnyebben olvasható teljes if utasítással.

2.11.3. Beágyazás és korai visszatérések

A feltételes utasítások tetszőlegesen mélyen beágyazhatók, de a behúzás minden további rétege nehezebben olvashatóvá tesz egy függvényt. Az alábbi példa négy feltételt ellenőriz, mielőtt elvégezné a valódi munkát, és a hasznos sort négy behúzásnyi mélyen hagyja eltemetve:

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

Két minta lapítja ki az ilyen jellegű kódot.

2.11.3.1. Korai visszatérések őrfeltételekhez

Kezeld először minden „kiszállási” esetet, mindegyiket saját return utasítással, hogy a fő logika a külső behúzási szinten maradjon. Minden őrfeltétel így olvasandó: „ez nem olyan eset, amelyet kezelünk; lépj ki”:

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)

A „fő útvonal” most egyetlen sor a függvény alján, nem pedig négy réteg belsejébe temetve. Ezt a stílust néha őrfeltétel-mintának (guard clause) nevezik.

2.11.3.2. Tesztek kombinálása az and / or operátorokkal

Amikor több feltételnek is teljesülnie kell ugyanahhoz az ághoz, kombináld őket az and operátorral a beágyazás helyett. Azok a feltételek, amelyek egyenként, önállóan kiváltják az ágat, az or operátorral kombinálhatók:

# 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

Mindkét forma rövidre zár, így a jobb oldalon lévő költséges ellenőrzés csak akkor fut le, amikor a bal oldali olcsóbb ellenőrzések még nem rendezték a kérdést.