2.11. Ehtolauseet

Ehtolause suorittaa koodilohkon vain silloin, kun jokin testi arvioituu todeksi. Avainsana on if, jota voi valinnaisesti seurata yksi tai useampi elif (”else if”) -haara ja lopullinen else.

n = 42

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

Kunkin haaran runko on kaikki sen alle sisennetty (sopimuksen mukaan neljä välilyöntiä). Python käy haarat läpi järjestyksessä, suorittaa ensimmäisen, jonka testi on tosi, ja ohittaa loput. else-lohko suoritetaan vain, jos jokainen edeltävä testi oli epätosi; se on aina valinnainen.

Vuokaavio, joka näyttää if/elif/else: kaksi vinoneliön muotoista päätöstestiä runkoineen, jotka putoavat lopulliseen else- runkoon, kun molemmat testit ovat epätosia.

Vain yksi haara suoritetaan koskaan. Testit arvioidaan ylhäältä alas, kunnes yksi onnistuu; loput ohitetaan.

2.11.1. Totuusarvoisuus

if-lauseen testin ei tarvitse palauttaa True tai False – mikä tahansa arvo lasketaan joko todenkaltaiseksi tai epätodenkaltaiseksi. Epätodenkaltaiset arvot ovat:

  • False ja None

  • Luku nolla: 0, 0.0

  • Tyhjät jonot ja kokoelmat: "", [], (), {}, b""

Kaikki muu on todenkaltaista. Tämä antaa sinun kirjoittaa tiiviitä testejä:

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

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

Huomaa, että totuusarvoisuus muuttaa merkityksen. if value: ei ole sama kuin if value is not None: – ensimmäinen on epätosi myös silloin, kun value on 0 tai "". Kun todella tarkoitat ”onko tämä täsmälleen None”, käytä eksplisiittisesti is None / is not None.

2.11.2. Ehtolausekkeet (ternary)

Ehtolause voi esiintyä lausekkeen sisällä:

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

Luetaan ”label on "even" jos n % 2 == 0 muuten "odd".” Kätevä yksirivisille; mihin tahansa yhtä riviä pidempään täysi if-lause on helpompi lukea.

2.11.3. Sisäkkäisyys ja varhaiset paluut

Ehtolauseet voivat olla sisäkkäin mielivaltaisen syvälle, mutta jokainen ylimääräinen sisennystaso tekee funktiosta vaikeammin luettavan. Alla oleva esimerkki tarkistaa neljä ehtoa ennen varsinaista työtä ja jättää hyödyllisen rivin hautautuneeksi neljän sisennyksen taakse:

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

Kaksi kuviota litistää tämänkaltaista koodia.

2.11.3.1. Varhaiset paluut vartijoina

Käsittele jokainen ”keskeytä”-tapaus ensin, kukin omalla return-lauseellaan, jotta päälogiikka pysyy uloimmalla sisennyksellä. Kukin vartija luetaan ”tämä ei ole tapaus, jonka käsittelemme; poistu”:

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)

”Pääpolku” on nyt yksi rivi funktion alaosassa, ei hautautuneena neljän kerroksen sisään. Tätä tyyliä kutsutaan joskus vartijaehdon (guard clause) kuvioksi.

2.11.3.2. Testien yhdistäminen and / or -operaattoreilla

Kun useiden ehtojen on kaikkien pädettävä samaan haaraan, yhdistä ne and-operaattorilla sisäkkäisyyden sijaan. Ehdot, jotka kukin itsenäisesti laukaisevat haaran, yhdistetään or-operaattorilla:

# 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

Molemmat muodot oikosulkevat, joten kallis tarkistus oikealla puolella suoritetaan vain, kun vasemmalla olevat halvemmat tarkistukset eivät ole jo ratkaisseet kysymystä.