2.11. Condiționale

O condițională rulează un bloc de cod doar atunci când un anumit test se evaluează la adevărat. Cuvântul-cheie este if, urmat opțional de una sau mai multe ramuri elif („else if”) și de un else final.

n = 42

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

Corpul fiecărei ramuri este tot ceea ce este indentat sub ea (patru spații prin convenție). Python parcurge ramurile în ordine, rulează prima al cărei test este adevărat și le omite pe celelalte. Blocul else rulează doar dacă fiecare test precedent a fost fals; este întotdeauna opțional.

O diagramă de flux care arată if/elif/else: două teste de decizie în formă de romb cu corpurile lor, ajungând la un corp else final atunci când ambele teste sunt false.

O singură ramură rulează vreodată. Testele sunt evaluate de sus în jos până când unul reușește; restul sunt omise.

2.11.1. Valoarea de adevăr

Un test dintr-un if nu trebuie să returneze True sau False – orice valoare contează fie ca truthy, fie ca falsy. Valorile falsy sunt:

  • False și None

  • Numărul zero: 0, 0.0

  • Secvențe și colecții vide: "", [], (), {}, b""

Orice altceva este truthy. Acest lucru îți permite să scrii teste compacte:

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

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

Fii conștient că valoarea de adevăr schimbă sensul. if value: nu este același lucru cu if value is not None: – prima este de asemenea falsă atunci când value este 0 sau "". Când chiar te referi la „este acesta exact None„, folosește explicit is None / is not None.

2.11.2. Expresii ternare

O condițională poate apărea în interiorul unei expresii:

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

Se citește ca „label este "even" dacă n % 2 == 0 altfel "odd".” Util pentru construcții pe o singură linie; pentru orice depășește o linie, o instrucțiune if completă este mai ușor de citit.

2.11.3. Imbricare și returnări timpurii

Condiționalele pot fi imbricate arbitrar de adânc, dar fiecare strat suplimentar de indentare face o funcție mai greu de citit. Exemplul de mai jos verifică patru condiții înainte de a efectua munca reală și lasă linia utilă îngropată la patru niveluri de indentare:

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

Două șabloane aplatizează acest tip de cod.

2.11.3.1. Returnări timpurii pentru gărzi

Tratează mai întâi fiecare caz de „abandon”, fiecare cu propriul return, astfel încât logica principală să rămână la indentarea exterioară. Fiecare gardă se citește ca „acesta nu este un caz pe care îl tratăm; ieși”:

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)

„Calea principală” este acum o singură linie la baza funcției, nu îngropată în interiorul a patru straturi. Acest stil este uneori numit șablonul guard clause (clauză de gardă).

2.11.3.2. Combinarea testelor cu and / or

Când mai multe condiții trebuie să fie toate îndeplinite pentru aceeași ramură, combină-le cu and în loc să le imbrici. Condițiile care declanșează fiecare independent ramura se combină cu 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

Ambele forme efectuează evaluare prin scurtcircuit, așa că o verificare costisitoare din partea dreaptă rulează doar atunci când verificările mai ieftine din stânga nu au soluționat deja problema.