Pogoji in zanke

Tema drugega predavanja so pogojni stavki in zanke. Kdor zna programirati, to že pozna. Razložil bom samo razliko med zapisom teh reči v jezikih, ki jih poznate, in zapisom v Pythonu, zraven pa še par Pythonovih posebnosti.

Tole je program, ki izračuna število členov Collatzovega zaporedja, ki se začne s podanim številom n. Kaj je Collatzovo zaporedje, ni pomembno.

n = 42
clenov = 1;
while (n != 1) {
    if (n % 2 == 0) {
        n /= 2;
    }
    else {
        n = 3 * n + 1;
    }
    clenov += 1;
}

To ni Python. Lahko bi bil C, C++, Javascript ... Približno katerikoli jezik, v katerem so vas učili programirati, če vas niso v Pythonu. Na tri stvari bomo pozorni.

Tule je ista reč v Pythonu.

n = 42
clenov = 1
while n != 1:
    if n % 2 == 0:
        n /= 2
    else:
        n = 3 * n + 1
    clenov += 1

Prvo: Bloki in zamiki

Tudi programi v Pythonu imajo bločno strukturo, vendar brez zavitih oklepajev. Blok začnemo z dvopičjem. Potem pa veljajo zamiki. Medtem ko se jih moramo v Cju držati zato, da je program berljiv, se jih moramo v Pythonu držati zato, da je pravilen.

Spodnje ni OK, ker je clenov += 1 nekje vmes - ne v else, ne zunaj:

clenov = 1
while n != 1:
    if n % 2 == 0:
        n /= 2
    else:
        n = 3 * n + 1
      clenov += 1

Spodnje ni OK, ker bi morala biti if in else na istem nivoju:

n = 42
clenov = 1
while n != 1:
    if n % 2 == 0:
        n /= 2
        else:
        n = 3 * n + 1
    clenov += 1

Spodnje ni OK, ker bi moral biti n /= 2 zamaknjen:

n = 42
clenov = 1
while n != 1:
    if n % 2 == 0:
    n /= 2
    else:
        n = 3 * n + 1
    clenov += 1
return clenov

Vse to je očitno narobe. Vi samo pravilno zamikajte, pa bo vse v redu.

Praviloma zamikamo za štiri presledke. Če hočete, lahko tudi za dva ali samo enega, ampak to ni berljivo.

clenov = 1
while n != 1:
 if n % 2 == 0:
  n /= 2
 else:
  n = 3 * n + 1
 clenov += 1

Lahko tudi za petnajst, ampak to bi bilo videti tako:

clenov = 1
while n != 1:
               if n % 2 == 0:
                              n /= 2
               else:
                              n = 3 * n + 1
               clenov += 1

Presledki ali tabulatorji? Presledki. Tabulatorji so tolerirani. Mešanica pa je prepovedana - Python v tem primeru javi napako.

Drugo: Oklepaji

Python poskuša biti zračen. Kot ste videli, pri while in if ne zapiramo pogojev v oklepaje, ker ... zakaj bi jih?

Mogoče se vam zdi, da je z njimi pregledneje. To se vam zdi zato, ker ste tako navajeni iz C-ja. V Pythonu pišite brez njih. Ker je tako zmenjeno. In hitro se vam bo zdelo v Pythonu pregledneje brez, v C-ju pa z. Dober programer prevzame navade jezika. V Pythonu pišemo oklepaje samo tam, kjer so potrebni, recimo zaradi prednosti operatorjev.

Tretje: Konci vrstic

V Cju konec stavka označimo s podpičjem. V Pythonu konec stavka označimo tako, da gremo v novo vrstico. Zato ne smemo kar tako brez zveze lomiti vrstic.

V C-ju smemo napisati

while (n != 1) {
    if (n % 2 == 0) {
        n 
        /= 2;
    }

V Pythonu pa ne. Tam, kjer gremo v novo vrstico, je tako, kot če bi v Cju naredili podpičje. No, obstajata dva načina, da prelomimo vrstico, ne da bi Python to dojel kot konec vrstice. Ampak to bomo videli sproti, ko bo potrebno.

Mogoče boste opazili, da lahko tudi v Pythonu uporabljate podpičja. Ostala so iz zgodovinskih razlogov. Noben resen programer v Pythonu jih ne piše. Tudi vi jih ne pišite.

Pogojni stavki

Pogoje očitno pišemo z if in else. Tu pride do male zafrkancije, ko stvari nizamo. V Cju bi lahko pisali

if (nekaj) {
    ...
}
else if (nekaj_drugega) {
    ...
}
else if (nekaj_tretjega) {
    ...
}
else {
    ...
}

V Pythonu bi to izgledalo tako

if nekaj:
    ...
else:
    if nekaj_drugega:
        ...
    else:
        if nekaj_tretjega:
            ...
        else:
            ...

To ni kul, iz dveh razlogov. Prvi je, da lezemo vedno bolj na desno. Drugi je, da je v C-jevskem primeru program jasnejši: ima tri alternative (nekaj, nekaj_drugega in nekaj_tretjega) ter rezervni scenarij. Vsi so nekako na istem nivoju - zgodi se prvo, drugo ali tretje. V Pythonu pa je videti, kot da se situacija, kjer nekaj ni res, razdeli na dve podvarianti, in če nekaj_drugega ni res, imamo spet dve podvarianti.

Za take primere imamo v Pythonu poleg if in else še elif.

if nekaj:
    ...
elif nekaj_drugega:
    ...
elif nekaj_tretjega:
    ...
else:
    ...

Zanke

Videli smo while. Ta deluje čisto tako kot while v drugih jezikih. Tudi break in continue imamo. Posebnost je, da ima while lahko še else. Ampak ta else je bolj zanimiv v kombinaciji s for, tako da ga bomo spoznali takrat, ko se bomo učili o for-u. Ta pa je precej drugačen od tistega, ki ste ga navajeni in bo vreden posebnega predavanja. Zanke do - while (ali repeat - until) pa v Pythonu ni. V resnici jo tudi v jezikih, ki jo imajo, zelo redko potrebujemo.

Pogoji

==, !=, <, >, <= in >= delujejo tako, kot ste jih navajeni. Ena lepa stvar v Pythonu je, da jih lahko nizamo: if a < b < c: ali if 10 <= a == b <= 20. Slednje pomeni, da morata biti a in b enaka ter morata biti med 10 in 20. Ali pa tole: if x < 10 < y:: x mora biti manjši od 10, y pa večji. Možne so tudi poljubne bedaste kombinacije, if 10 <= a >= b == 3 > x:, ampak tega seveda ne počnemo. Celo če je slučajno smiselno in pravilno, ni berljivo.

S temi operatorji lahko primerjamo tudi nize in še vse žive druge reči. Če nize primerjamo po velikosti, jih primerja po abecedi. Vsaj dokler gre za črke angleške abecede.

Python se trudi biti berljiv in zračen, zato pogojev ne sestavljamo z &&, || in !, temveč and, or in not.

Konstanti True in False se pišeta z veliko začetnico. Kot sem ju pravkar napisal.

Zanimivost: razred bool je izpeljan iz razreda int. True je samo malo drugače izpisano število 1 in False je samo malo drugače izpisana 0. True + True je 2. Ampak to je samo neuporabna zanimivost.

Pogoji se računajo samo, do koder je treba. 5 > 6 and 1 / 0 > 12 ne javi deljenja z 0 temveč False. Ker je že 5 > 6 neresnično in mu potem sledi and, Python ne vidi potrebe, da bi računal še naprej. (To je enako tudi v Cju in vseh drugih normalnih jezikih.) Podobno 5 < 6 or 1 / 0 > 12 ne vrne napake, ker je že 5 < 6 resnično in ne vidi potrebe, da bi gledal še desno od or-a.