În cadrul acestui episod vom vedea cum putem face în așa fel încât programele să ia anumite decizii în funcție de circumstanțe.
Până acum am scris doar programe sau scurte secvențe de cod în care instrucțiunile se executau în ordine, începând cu prima și terminând cu ultima. Nimic nu putea afecta acest proces. Dar, programele trebuie să poată face mai mult decât atât...
Să ne imaginăm că ajungem la o răscruce de drumuri; cel din dreapta duce spre Împărăția Roșie, iar celălalt spre Împărăția Verde. În funcție de unde vrem să ajungem, vom alege drumul din dreapta sau cel din stânga.
Pentru a o lua la dreapta, trebuie ca o anumită condiție să fie îndeplinită; trebuie să vrem să mergem în Împărăția Roșie. Pentru a o lua la stânga, trebuie ca acea condiția să nu fie îndeplinită; trebuie să nu vrem să mergem în Împărăția Roșie, ceea ce înseamnă că vrem să mergem în Împărăția Verde.
Condiția poate lua diverse forme. În exemplul anterior condiția a fost voința noastră; dar, ar putea să fie ceva mai interesant; de exemplu, am putea spune că dacă în caleașca pe care o însoțim se află o prințesă, atunci vom merge în Împărăția Roșie.
Instrucțiunea if
Pentru a explica ce vrem să facem, am folosit cuvântul dacă; am spus că dacă o anumită condiție este îndeplinită vom efectua o anumită acțiune. Și în Python vom folosi ceva similar; va fi în engleză, deci cuvântul va fi if. El va fi urmat de condiția care trebuie verificată și de : , iar apoi de instrucțiunea care trebuie executată în cazul în care condiția este îndeplinită. Condiția este o expresie booleană; poate fi o simplă variabilă sau o expresie mai complexă. O astfel de instrucțiune este numită condițională.
Să presupunem că avem o variabilă exista_printesa care are o anumită valoare; nu știm exact cum a fost atribuită acea valoare și nici care este valoarea sa curentă. Dar, dacă în acest moment această variabilă are valoarea True, dorim să scriem mesajul "Împărăția Roșie". Secvența de cod ar arăta astfel:
1 |
if exista_printesa: print("Împărăția Roșie") |
Secvența este corectă, dar nu arată prea bine. De obicei instrucțiunea care ar trebui executată atunci când este îndeplinită condiția este scrisă pe o linie nouă.
1 2 |
if exista_printesa: print("Împărăția Roșie") |
Blocuri de instrucțiuni
Deocamdată, dacă este îndeplinită condiția executăm o singură instrucțiune. Dar, s-ar putea să vrem să executăm mai multe. De exemplu, am putea să vrem să ducem prințesa în Împărăția Roșie și să o lăsăm acolo; când ajunge acasă, prințesa va coborî din caleașcă, deci în caleașcă nu se va mai afla nicio prințesă. Așadar, variabila exista_printesa ar trebui să primească valoarea False. Am putea verifica din nou dacă este îndeplinită condiția; codul ar putea fi următorul:
1 2 3 4 5 |
if exista_printesa: print("Împărăția Roșie") if exista_printesa: exista_printesa = False |
Nu arată deloc bine... Ce am vrea este să scriem condiția o singură dată și să executăm mai multe instrucțiuni. Pentru aceasta va trebui să creăm un așa numit bloc de instrucțiuni. Un astfel de bloc este format dintr-o succesiune de instrucțiuni. Putem rescrie secvența astfel:
1 2 3 |
if exista_printesa: print("Împărăția Roșie") exista_printesa = False |
În Python, un bloc de instrucțiuni este definit de numărul de spații dintre instrucțiune și marginea din stânga a ecranului, adică de indentare. De regulă, se folosesc spațiile libere pentru indentare, iar numărul lor este un multiplu de 2. Standard-ul Python, sugerează să folosim patru spații, dar decizia ne aparține. Desigur, putem folosi și indentarea cu Tab, însa nu putem folosi și Tab și spații.
De asemenea, numărul de spații sau de tab-uri folosite, într-un bloc de instrucțiune, trebuie să fie aceelași. Codul următor nu va fi funcțional:
1 2 3 |
if exista_printesa: print("împărăția Roșie") exista_printesa = False |
Altfel de condiții
Spuneam că acea condiție este o expresie booleană. Până acum am folosit o simplă variabilă booleană; este ușor să ne gândim că putem folosi operatorii booleeni pe care i-am prezentat în episodul trecut. Poate dacă în caleașcă se află și un prinț, dorim de fapt să mergem la nunta din Împărăția Verde. Codul ar putea arăta așa:
1 2 |
if exista_printesa and exista_print: print("Împărăția Verde") |
Dar, de obicei condițiile pe care dorim să le verificăm sunt cu totul altele. Dacă lucrăm cu numere, am putea dori să verificăm dacă un număr are o anumită valoare, să vedem dacă un număr este mai mare decât altul etc.
Să considerăm un prim exemplu: avem o variabilă nr care conține un număr întreg; în cazul în care valoarea acelei variabile este 2457, dorim să scriem mesajul "Număr magic". Codul este:
1 2 |
if nr == 2457: print("Număr magic") |
Observăm că nu am scris un singur simbol =, ci două; == este operatorul de egalitate. Folosim un singur = pentru atribuire. Secvența următoare nu este validă:
1 2 |
if nr = 2457: print("Număr magic") |
Operatorul de egalitate este aplicat asupra a doi operatori cu tipuri compatibile; pentru tipurile primitive nu avem nicio surpriză; rezultatul este o valoare booleană care arată dacă cele două valori sunt egale.
Avem și un operator de inegalitate; rezultatul arată dacă cele două valori nu sunt egale.
1 2 |
if nr != 2457: print("Numărul nu este magic!") |
După cum vedeți, operatorul este !=. Intuitiv, am putea spune că am negat egalitatea; am folosit semnul exclamării (cel care indică negația) urmat de semnul egal.
Dar, numerele pot fi și comparate; nu ar trebui să ne surprindă deloc existența unor operatori ca < sau >. Să verificăm dacă un număr este strict pozitiv:
1 2 |
if nr > 0: print("Număr strict pozitiv!") |
La fel de simplu este să verificăm dacă numărul este strict negativ:
1 2 |
if nr < 0: print("Număr strict negativ!") |
Când comparăm numerele folosim câteodată și conceptul de mai mare sau egal. Avem și un operator pentru așa ceva; nu este chiar ≥ cum poate ne-ar plăcea, ci >=. Să vedem cum verificăm dacă un număr este pozitiv (nu strict pozitiv):
1 2 |
if nr >= 0: print("Număr pozitiv!") |
Similar, avem operatorul <= pentru mai mic sau egal.
Condiții compuse
Rezultatul utilizării oricărui astfel de operator este o valoare booleană; este natural să ne așteptăm să putem folosi operatorii booleeni asupra rezultatelor.
Am putea dori să verificăm dacă un anumit număr întreg este format dintr-o singură cifră. Am avea condiția dublă: numărul trebuie să fie mai mare sau egal cu zero și mai mic decât zece. Am putea scrie următorul cod:
1 2 |
if nr >= 0 and nr < 10: print("O cifră") |
Mai avem și alte variante; una ar putea fi:
1 2 |
if nr > -1 and nr <= 9: print("O cifră") |
Codul funcționează corect fiindcă operațiile de comparare sunt executate înaintea conjucției logice; există o ordine specifică limbajului și de data aceasta ordinea de convine; dar, ar fi cam mult să ținem minte ordinea luată în considerare de limbaj; de obicei vrem să ne asigurăm că operațiile sunt efectuate în ordinea pe care o dorim; pentru aceasta folosim paranteze, chiar dacă nu sunt neapărat necesare; codul poate fi înțeles mult mai ușor. Așadar, varianta recomandată ar fi:
1 2 |
if (nr >= 0) and (nr < 10): print("O cifră") |
Deși nu prea are sens să scriem un astfel de cod, pentru a ilustra că nu tot timpul ordinea este cea pe care am dori-o să verificăm dacă un număr este diferit de 2457 verificând egalitatea și negând rezultatul. Codul ar arăta așa:
1 2 |
if not nr == 2457: print("Numărul nu este magic!") |
Dacă avem and și prima dintre cele două condiții este falsă, atunci a doua nu mai este verificată fiindcă rezultatul ar fi False oricum. Similar, dacă avem or și prima dintre cele două condiții este adevărată, atunci a doua nu mai este verificată fiindcă rezultatul ar fi True oricum. Deocamdată nu pare foarte important; dar, dacă ne gândim că aceste condiții pot deveni din ce în ce mai complicate, ne putem imagina că am putea ajunge să economisim timp dacă nu facem verificări inutile. Să revenim la codul care verifică dacă un număr are o singură cifră:
1 2 |
if ((nr >= 0) and (nr < 10)): print("O cifră") |
Dacă numărul ar fi negativ, prima condiție este falsă și nu mai are rost să verificăm dacă el este mai mic decât zece. Chiar dacă ar fi (și în cazul nostru știm că va fi fiindcă este negativ), nu are nicio relevanță; condiția compusă va fi falsă.
Alternativa
Să revenim la exemplul inițial; spuneam că dacă avem o prințesă în caleașcă vrem să mergem în Împărăția Roșie. Probabil că dacă nu însoțim nicio prințesă am vrea totuși să mergem în Împărăția Verde (poate găsim o prințesă acolo?). Pentru a verifica dacă trebuie să mergem în Împărăția Verde, am putea nega condiția; codul ar arăta astfel:
1 2 3 4 5 |
if exista_printesa: print("Împărăția Roșie") if not exista_printesa: print("Împărăția Verde") |
Deocamdată nu avem nicio problemă, dar pare complicat și ne putem imagina că în situații complexe ar deveni din ce în ce mai ciudat. Codul pe care l-am scris ar putea fi descris astfel: dacă în caleașcă este o prințesă mergem în Împărăția Roșie; dacă în caleașcă nu este o prințesă mergem în Împărăția Verde. Pare puțin ciudat și cam lung; ne-am aștepta ca raționamentul să fie ceva de genul: dacă în caleașcă este o prințesă mergem în Împărăția Roșie; altfel mergem în Împărăția Verde. Din fericire, Python și majoritatea limbajelor de programare ne permit să "spunem" altfel. Cuvântul va fi în engleză: else.
În Python vom avea cuvântul if, urmat de condiția care trebuie verificată, de semnul :, de instrucțiunea care trebuie executată în cazul în care condiția este îndeplinită, apoi de cuvântul else, din nou de semnul : și de instrucțiunea care trebuie executată în cazul în care condiția este îndeplinită.
Codul nostru devine:
1 2 3 4 |
if exista_printesa: print("Împărăția Roșie") else: print("Împărăția Verde") |
If în if
Am spus că în cazul în care este îndeplinită o condiție se execută o instrucțiune. Am mai arătat că dacă nu este îndeplinită condiția, putem specifica o altă instrucțiune care să fie executată. Nu am pus nicio restricție legată de tipul instrucțiunilor respective. De fapt, nu există nicio restricție. Am văzut că putem pune o instrucțiune simplă sau un bloc de instrucțiuni. Dar, putem pune chiar și o altă instrucțiune condițională. De fapt, și printre instrucțiunile care formează un bloc, oricare poate fi un if.
Așadar, putem verifica o condiție și apoi, printre operațiile pe care le efectuăm, putem verifica o altă condiție și efectua alte operații în funcție de ea.
Să extindem puțin exemplul inițial; la răscrucea de drumuri putem alege trei variante: spre Împărăția Roșie, spre Împărăția Verde sau spre Împărăția Albastră. În caleașcă putem avea sau nu o prințesă și putem sau nu avea un prinț. Dacă prințesa nu este în caleașcă, atunci mergem în Împărăția Albastră să aducem prințesa; dacă e în caleașcă și nu e însoțită, mergem în Împărăția Verde să luăm prințul; dacă e însoțită de prinț, mergem la nuntă în Împărăția Roșie.
Așadar, vom avea o condiția care verifică dacă prințesa există. Dacă da, atunci trebuie să verificăm dacă există și prințul. Dacă prințul există, scriem mesajul "Împărăția Roșie". Dacă prințul nu există, scriem mesajul "Împărăția Verde". Dacă prințesa nu există, scriem mesajul "Împărăția Albastră" indiferent dacă prințul există sau nu.
Codul ar putea arăta așa:
1 2 3 4 5 6 7 |
if exista_printesa: if exista_print: print("Împărăția Roșie") else: print("Împărăția Verde") else: print("Împărăția Albastră") |
Nu trebuie neapărat să ne oprim la un singur if în if. Cel din interior poate conține la rândul său o instrucțiune condițională; la fel acest al treilea if și așa mai departe.
Când avem două sau mai multe astfel de instrucțiuni if, spunem că ele sunt imbricate.
Va urma
În următorul episod vom vedea ce opțiuni avem la dispoziție în cazul în care o anumită variabilă (sau expresie) poate avea diferite valori și trebuie să executăm diverse instrucțiuni în funcție de fiecare valoare în parte.