Copyright 2020 L&S SOFT
Toate drepturile asupra acestei lucrǎri aparţin editurii L&S SOFT.
Reproducerea integralǎ sau parţialǎ a textului din aceastǎ carte este
posibilǎ doar cu acordul în scris al editurii L&S SOFT.
ISBN: 978-606-94898-1-9
Coperta realizată de Vlad Eric TUDOR
ATENȚIE!
După confirmarea plății, fiecare carte poate fi descărcată de
maximum 5 ori şi este disponibilă 30 de zile.
Fiecare PDF este securizat în 28 de zone cu watermark invizibil
(id comandă, e-mail, nume) pentru a nu putea fi distribuit
pe alte căi virtuale.
Adresa: Aleea Aviatiei nr. 10, Voluntari, Ilfov;
Mobil: 0727.731.947;
E-mail: comenzi@ls-infomat.ro;
www.ls-infomat.ro
www.manuale-de-informatica.ro
Biblioteca Digitală de Informatică “Tudor Sorin”
www.infobits.ro
Volumul I – Fundamente pentru începători
Alfa. Introducere
De ce Python?
Python, un limbaj interpretat
Python 2 vs. Python 3
9
9
10
10
Beta. Instalarea mediului de programare Python
Acces rapid la Python IDLE
11
13
Gama. Modul de lucru în Python
Crearea și salvarea unui program
Rularea unui program
Deschiderea unui program
Închiderea unui program
Fișiere recente
Comenzi uzuale ale editorului de text
Ștergerea consolei din Python IDLE
Executarea codului din Command Prompt
IDE-uri
Recapitulare
15
16
17
18
18
18
18
19
19
20
20
Capitolul 1. Primele noțiuni
1.1. Câte ceva despre programe
1.2. Ce sunt variabilele?
21
21
23
1.2.1. Care este mecanismul?
1.2.2. Definirea variabilelor în Python
1.2.3. Hei!.. 2 + 3 nu fac 23!?!
1.3. Vocabularul limbajului
24
25
28
29
1.3.1. Setul de caractere
1.3.2. Identificatori
1.3.3. Separatori
1.3.4. Comentarii
29
30
30
31
3
1.4. Tipuri de date
31
1.4.1. Tipuri de date numerice
1.4.2. Șiruri de caractere
1.4.3. Date numerice vs. șiruri de caractere
32
34
35
1.5. Mai multe moduri de atribuire
1.6. Funcția type
1.7. Operații aritmetice elementare introductive
1.8. Ce este un algoritm?
Probleme propuse / exerciții
36
37
37
41
43
Capitolul 2. Expresii
2.1. Introducere
2.2. Operatori în Python
46
46
49
2.2.1. Operatori aritmetici
2.2.2. Operatori relaționali
2.2.3. Operatori logici
2.2.4. Valori booleene
2.2.5. Operatori de atribuire
50
53
55
57
59
2.3. Erori frecvente
2.4. Câteva funcții utile (built-in)
60
62
2.4.1. Funcția abs()
2.4.2. Funcția eval()
2.4.3. Funcția id()
2.4.4. Funcția len()
2.4.5. Funcția round()
62
63
64
64
65
2.5. Mai mult despre print()
Probleme rezolvate
Probleme propuse / exerciții
66
67
69
Capitolul 3. Fără OOP nu putem continua...
Înțelegeți la nivel de bază conceptele de încapsulare, clasă,
obiect, instanțiere, date și metode membru – 3 pagini esențiale!
71
Capitolul 4. Șiruri de caractere
4.1. Introducere
4.2. Operatorii + (concatenarea) și * (repetiția)
74
74
75
4
4.3. Accesul la caracterele șirului
4.4. Lungimea unui șir de caractere
4.5. Subșiruri (feliere, în engleză slicing)
4.6. Apartenența – in și not in
4.7. Funcțiile built-in min() și max()
4.8. O parte dintre metodele clasei str
4.9. Compararea șirurilor
4.10. Formatarea șirurilor
Probleme rezolvate/propuse
76
78
78
80
80
81
85
86
89
Capitolul 5. Colecții de date
5.1. Liste
92
92
5.1.1. Ce este o listă?
5.1.2. Accesul la elemente
5.1.3. Modificarea elementelor
5.1.4. Ștergerea elementelor
5.1.5. Adăugarea elementelor noi
5.1.6. Extinderea unei liste
5.1.7. Operatorii +, *, in și not in
5.1.8. Alte metode și funcții built-in utile
5.1.9. Exerciții propuse
5.2. Tupluri
92
93
94
94
95
97
97
98
100
101
5.2.1. Ce este un tuplu?
5.2.2. Accesul la elemente
5.2.3. Lungimea unui tuplu
5.2.4. Operatorul in și grupul not in
5.2.5. Constructorul clasei tuple
5.2.6. Ștergerea unui tuplu
5.2.7. Operatorii + și *
5.2.8. Metodele clasei tuple
5.2.9. Modificare unui tuplu – un truc interesant!
5.3. Seturi
101
102
102
102
103
104
104
105
106
107
5.3.1. Ce este un set de date?
5.3.2. Adăugarea de noi elemente
5.3.3. Ștergerea elementelor
5.3.4. Operații cu mulțimi
5.3.5. Clasa frozenset
5.4. Dicționare
107
108
109
110
111
112
5.4.1. Ce este un dicționar?
112
5
5.4.2. Clasa dict
5.4.3. Metoda get()
5.4.4. Modificarea și adăugarea perechilor de date
5.4.5. Din nou despre operatorii in și not in
5.4.6. Revenim la frozenset...
Capitolul 6. Instrucțiunile limbajului Python
6.1. Instrucțiunea condițională If
6.1.1. Forma if .. else
6.1.2. Forma if .. elif .. else
6.1.3. Instrucțiunea compusă. Indentarea!
6.1.4. Probleme rezolvate
6.1.5. Case/switch nu există...
6.1.6. Exerciții propuse
6.2. Instrucțiunea repetitivă for
113
114
115
115
116
117
117
117
119
120
122
127
129
130
6.2.1. Forma generală
6.2.2. Funcția range(). Forma clasică pentru for
6.2.3. Probleme rezolvate
6.2.4. Citirea colecțiilor de date de la tastatură
6.2.5. Mai mult despre user-friendly
6.2.6. Exerciții propuse
6.3. Instrucțiunea repetitivă while
130
133
134
139
140
143
6.3.1. Probleme rezolvate
6.3.2. Exerciții propuse
144
148
6.4. Clauzele break și continue
149
6.3.1. Clauza break
6.3.2. Clauza continue
149
149
Capitolul 7. La voia întâmplării...
7.1. Numere aleatoare
7.2. Cum le putem genera în Python?
150
150
150
7.2.1. Importarea primului nostru modul – random
7.2.2. Funcția randint
7.2.3. Funcția choice
7.2.4. Funcția shuffle
7.2.5. Funcția seed
7.3. Primele jocuri în Python
150
152
153
154
154
156
7.3.1. Ghicește numărul!
156
6
7.3.2. Tabla înmulțirii – crearea unui test de evaluare
7.3.3. Spânzurătoarea - țări din Uniunea Europeană
Capitolul 8. Funcții și module
8.1. Introducere
8.2. Funcții
158
162
169
169
170
8.2.1. Crearea unei funcții
8.2.2. Să formăm un prim modul!
8.2.3. Mai mulți parametri formali
8.2.4. Valori implicite pentru parametri
8.2.5. Funcții anonime – lambda
8.2.6. Probleme rezolvate
8.2.7. Probleme propuse
8.3. Vizibilitatea variabilelor
170
173
176
178
179
180
185
186
8.3.1. Variabile locale și globale
8.3.2. Variabile nelocale
186
189
8.4. Transmiterea parametrilor
189
8.4.1. Introducere
8.4.2. Mai mult de spre variabile (mutabile / imutabile)
8.4.3. Stai! Cum copiez de fapt două variabile mutabile?
8.4.4. Revenim la transmiterea parametrilor
8.5. Poziția și ordinea scrierii funcțiilor
8.5.1. Ce înseamnă de fapt un limbaj interpretat?
8.5.2. Unde putem defini o funcție?
8.5.3. Mai multe funcții
8.5.4. Concluzii
8.6. Universul modulelor
189
190
192
194
196
196
197
197
198
199
8.6.1. Python Standard Library
8.6.2. Modulul math – fiți autodidacți!
Capitolul 9. I/O. Fișiere text
9.1. Introducere
199
200
201
201
9.1.1. Modelul black-box
9.1.2. Fișiere text
201
201
9.2. Deschiderea și închiderea unui fișierelor text
202
9.2.1. Un prim exemplu de citire
9.2.2. Întotdeauna închidem fișierul deschis...
9.2.3. Funcția open()
202
203
204
7
9.3. Citirea fișierelor text
205
9.3.1. Metoda read()
9.3.2. Conversia explicită spre o listă. Metoda readlines()
9.3.3. Metoda readline()
205
207
208
9.4. Scrierea fișierelor text
9.5. Cum ștergem un fișier?
209
212
Anexa 1. Diferențe dintre versiunile 2 și 3
213
Anexa 2. Tabela codurilor ASCII
214
Bibliografie
215
8
Introducere
Îmi doresc ca această carte să fie un curs introductiv solid de programare
în limbajul Python, cu informații precise și la obiect, explicate ușor, fără
multe detalii care vă pot face să pierdeți esența.
Limbajul Python este folosit la scară largă în prezent, fiind foarte popular,
simplu de învățat și de utilizat. Totul a pornit ca un hobbie de Crăciun
pentru Guido van Rossum în anul 1989 – fiind programator, a dorit să
dezvolte un interpretor de cod pentru limbajul la care visa; simplu, intuitiv,
open source, accesibil pe orice platformă. Deoarece urmărea cu drag
serialul difuzat de BBC – Monty Python’s Flying Circus, l-a numit Python.
De ce Python?
Cele mai importante avantaje sunt evidențiate mai jos:
ușor de învățat / predat – spre deosebire de alte limbaje de
programare, Python se înțelege foarte repede, chiar de la început;
ușor de folosit – Python este simplu și minimalist, apropiat de
pseudocod în limba engleză și permite ca atenția să fie focalizată
pe găsirea soluției problemei și nu utilizarea limbajului în sine;
gratuit și open source – este permisă redistribuirea limbajului,
a codului sursă, precum și editarea / modificarea acestuia pentru a
obține spre exemplu noi programe, deci poate fi și este îmbunătățit
de comunitate în mod constant;
portabil – limbajul Python poate fi utilizat pe o multitudine de
platforme / sisteme de operare, precum: Windows, GNU/Linux,
FreeBSD, Macintosh, Solaris, OS/2, PlayStation, etc.;
orientat pe obiecte – într-un mod foarte simplist și puternic, se pot
crea aplicații folosind Programarea Orientată pe Obiecte (POO);
9
Python, un limbaj interpretat
Limbajul Python este interpretat, adică se execută codul linie cu line, spre
deosebire de Pascal ori C/C++, unde este necesar un compilator care să
genereze un fișier executabil.
Programul Python este reținut pe hard-disk în limbajul Python și nu în cod
mașină, așa cum este în cazul celor compilate.
Detalii. Un program scris într-un limbaj ce necesită un compilator
este convertit la compilare din sursă în cod mașină, o succesiune de 0 și 1
(binar) care poate fi evaluată de către calculator. În linii mari, atunci când
programul este executat, mediul de programare copiază programul în
memoria internă și îl rulează. În cazul limbajului Python, nu este necesară
compilarea programului, acesta fiind executat direct din codul său sursă.
Intern, există anumite transformări a.î. sistemul respectiv să poată executa
programul, însă este mult mai simplu.
Programele Python sunt cu adevărat portabile. Un program scris corect
poate fi executat direct în Windows, precum și în GNU/Linux, de exemplu.
Python 2 vs. Python 3
Această carte este scrisă pentru versiunea 3 (mai exact, 3.8.0) deoarece
este ultima disponibilă în acest moment – fiind open-source, la fiecare
actualizare sunt rezolvate anumite probleme (bug-uri), ori sunt adăugate
elemente noi de limbaj, biblioteci, etc.
Atenție la ce versiune folosiți deoarece sunt diferențe semnificative între
2 și 3, iar se poate ca programele create într-una să nu funcționeze corect
în cealaltă! Țineți minte faptul că dacă învățați limbajul într-o versiune, vă
va fi foarte ușor să vă adaptați celeilalte, învățând diferențele dintre ele
(vezi Anexa 1. Diferențe dintre versiunile 2 și 3).
10
Instalarea mediului de programare Python
Accesați pagina oficială a limbajului Python, secțiunea Downloads, care are
adresa URL de mai jos:
https://www.python.org/downloads/
Eu am ales ultima versiune existentă în acest moment, Python 3.8.0, însă la
descărcare suntem anunțați că orice versiune peste 3.5 nu poate rula pe
sistemul de operare Windows XP (așadar, recomand 3.4.10 în acest caz).
Apăsați butonul corespunzător, salvați fișierul și deschideți-l apoi:
După ce fișierul a fost lansat, va apărea un panou unde vă recomand să
bifați înainte opțiunea de mai jos pentru a fi adăugate automat variabilele
de sistem necesare:
Porniți procesul de instalare apăsând butonul
(apăsând butonul Install Now, Python se va instala doar pentru utilizatorul
curent, iar modul de lucru va fi oarecum anevoios)
11
Lăsați totul bifat în prima fereastră:
În cea de-a doua însă, bifați opțiunea Install for all users:
Astfel, locația de instalare va fi în „C:\Program Files\Python38-32”,
accesibilă tuturor utilizatorilor (în cazul meu, versiunea 3.8, 32 de biți).
Apăsați butonul Install. Dacă totul a fost ok, apăsați Close.
12
Mediul este instalat cu succes pe sistemul vostru, dar implicit nu aveți
niciun shortcut spre Python pe Desktop, așa cum poate vă așteptați.
Ce facem acum?
Sistemul de operare prezentat este Windows, așadar apăsăm butonul
Start, apoi în bara de căutare scriem „IDLE”, apoi selectăm (în cazul meu)
Notă. IDLE semnifică Integrated Development and Learning Environment,
adică un mediu integrat de dezvoltare și învățare.
Se va deschide următoarea fereastră:
Super! De acum putem scrie cod în Python!
Mai sus aveți linia de comandă, consola (Interactive Python Shell),
iar poziția curentă este indicată prin cele trei caractere „>>>” și cursorul.
Scrieți „3 + 5” și apăsați tasta Enter,
13
iar Python v-a afișa imediat rezultatul.
Acces rapid la Python IDLE
Vă recomand să deschideți dosarul unde ați instalat Python, în cazul meu
C:\Program Files\Python38-32
apoi dosarul „Lib” și în interior, „idlelib”, unde veți găsi locația fișierului
„idle.bat”, asociat lui IDLE. Creați un shortcut pe Desktop către acest
program:
Eu am numit scurtătura „Python IDLE”.
Astfel putem deschide ușor mediul de programare Python direct de pe
Desktopul calculatorului nostru.
În secțiunea următoare veți învăța despre modul de lucru în Python.
14
Modul de lucru în Python
Considerăm că ați instalat corespunzător mediul de programare, precum
cele prezentate în secțiunea anterioară.
Primele comenzi
Limbajul Python este interpretat, adică execută codul linie cu line, spre
deosebire de Pascal ori C/C++, unde este necesar un compilator care să
genereze un fișier executabil. Consola, adică Python Interactive Shell, ne
oferă posibilitatea să executăm câte o comandă Python și să obținem
imediat rezulatul afișat.
Deschideți Python IDLE și introduceți comenzile pe rând, ca mai jos:
Calculul aritmetic a fost efectuat imediat și apoi tipărit rezultatul, iar cea
de-a doua comandă a fost reprezentată de funcția print care a afișat
mesajul – "Salut, Python!".
Inițial, modul de lucru direct în consolă pare interesant, diferit de cel
cunoscut poate până acum, însă avem totuși nevoie de programe care să
conțină mai multe linii de cod, redactate și executate împreună, pentru a
obține rezultate în urma unor calcule ori algoritmi elaborați.
Să vedem în continuare cum...
15
Crearea și salvarea unui program
Pentru a crea un program nou, alegem comanda New File din meniul File
(sau mai rapid, apăsând combinația de taste Ctrl+N). Se va deschide o
fereastră nouă unde putem scrie codul nostru Python (inițial vid, gol):
Scriem de exemplu trei comenzi, fiecare pe linia sa (important, veți vedea)
apoi apelăm comanda Save As, care deschide o nouă fereastră pentru a
putea reține pe disc fișierul. Am ales locația ca fiind Desktop-ul, iar fișierul
l-am numit „primul.py”.
Observații. Puteți reține fișierele de exemplu într-un dosar ori undeva pe
hard-disk-ul vostru, pentru a le grupa. Extensia fișierelor Python este „.py”,
implicit recomandată la salvare.
16
Rularea unui program
Primul nostru program fiind salvat, îl putem executa. Având fereastra
programului selectată, apăsați tasta F5 sau din meniu Run –> Run Module:
Rezultatul afișat de consolă este:
Ce s-a întâmplat? Unde sunt celelalte două rezultate? Dacă la nivel de
consolă putem scrie expresii aritmetice obținând direct rezultatul, în cadrul
programului Python putem scrie doar instrucțiuni, cum ar fi print. Așadar,
refacem programul folosind această instrucțiune, salvăm și apăsăm iar F5:
De această dată, toate datele / rezultatele au fost afișate în consolă (shell).
Acesta este modul de lucru uzual în Python... în editor scriem codul, iar în
consolă obținem rezultatul în urma rulării programului.
17
Deschiderea unui program
Să presupunem că am închis toate ferestrele și dorim apoi să redeschidem
programul anterior creat și salvat pe Desktop, numit „primul.py”.
Dacă efectuăm dublu asupra pictogramei, acesta se va rula automat în
consola sistemului de operare, în linia de comandă (cmd.exe), modul
de lucru este însă destul de anevoios (vezi pagina următoare).
Așadar, deschideți Python IDLE, apoi din meniul File, alegeți Open:
Selectați fișierul din locația respectivă și apăsați butonul Open.
Obs. Puteți avea deschise mai multe programe (ferestre) simultan.
Toate vor afișa rezultatele în unica fereastră Python IDLE.
Închiderea unui program
Pentru a închide programul / fereastra curentă, alegem din meniul File
comanda Close (mai rapid, combinația de taste Ctrl + F4).
Fișiere recente
Câteodată este util să avem acces la fișierele Python pe care le-am editat
recent. Din meniul File accesați Recent Files, apoi alegeți unul din listă.
Comenzi uzuale ale editorului de text
Mai mult decât cele prezentate anterior, în fereastra unui program Python
(a editorului), regăsiți comenzi uzuale de manipulare a textului, cum ar fi
Copy, Cut, Paste, Select All, Undo, Redo, Find, Replace, Go to Line, etc.
Le cunoașteți, sper, de la Tehnologia Informației...
18
Ștergerea consolei din Python IDLE
Nu există această posibilitate implicit, de aceea nici nu se găsește opțiunea
în meniu. Simplu - închideți și redeschideți fereastra Python IDLE.
Executarea codului din Command Prompt
Ați observat mai devreme că dacă efectuăm un dublu clic pe un program
Python, acesta este executat imediat de sistemul de operare, la nivel de
linie de comandă (Command Prompt, cmd.exe sau cmd).
Selectați meniul Start în Windows, căutați programul „cmd.exe” și apăsați
tasta Enter. Se va deschide linia de comandă, unde scrieți „python”:
Dacă totul este ok, iar căile spre Python au fost setate (bifată opțiunea
„Add Python 3.8 to PATH” la instalare), acesta este gata de lucru și precum
vedeți mai sus, am și executat o instrucțiune.
Pentru cei ce cunosc modul de lucru în linia de comandă, navigăm spre
Desktop, apoi pentru a rula programul „primul.py”, scriem comanda:
Nu vom folosi această variantă deoarece există, așa cum ați văzut, medii de
programare, precum IDLE, care simplifică modalitatea de lucru.
19
IDE-uri
Integrated Development Environment este un tip de aplicaţie care asistă
programatorul la dezvoltarea de software, oferindu-i acestuia un editor de
text performant, un compilator, un debugger şi multe alte componente
suplimentare, cum ar fi: diagramă cu ierarhia claselor, inspector de obiecte,
etc. Exemple de astfel de programe: Eclipse, Code::Blocks, Visual Studio
Code, NetBeans, etc. Editoarele de text sunt programe specializate folosite
pentru a scrie codul sursă, cu anumite particularități în funcție de limbajul
de programare utilizat, însă rudimentare în comparație cu orice IDE.
Bineînțeles că există și în cazul limbajului de programare Python o gamă
foarte variată în acest sens. Lista completă o găsiți pe pagina oficială:
https://wiki.python.org/moin/IntegratedDevelopmentEnvironments
Spre exemplu, dacă ați lucrat deja în Eclipse, care este un IDE open source
renumit, puteți instala extensia PyDev pentru a putea lucra în Python, ce
oferă o consolă interactivă, completarea automată a codului, depanarea
programelor, etc. (https://www.eclipse.org/, https://www.pydev.org/).
PyCharm este dedicat programării în Python, este gratuit (dar și plătit
pentru varianta profesională, cu suport pentru HTML, JavaScript, SQL) și se
instalează foarte ușor în Windows:
https://www.jetbrains.com/pycharm/download/#section=windows
Recapitulare
Așadar, primul pas este acela de a instala pe sistemul vostru mediul
de programare Python (în această carte, versiunea 3.8.0, S.O. Windows).
Apoi, pentru a vă fi mai ușor, creați un shortcut pe Desktop spre IDLE.
Modul de lucru la nivel de începător este ori direct în consolă, ori folosind
programe salvate pe disc care au extensia „.py”. În funcție de necesitate,
vom folosi în această carte una dintre cele două variante. Cu cât vom
avansa, a doua variantă va fi bineînțeles preferată.
Deoarece sunteți la început, folosim spre exemplificare inițial mediul
oficial, adică Python IDLE - e simplu și facil.
20
Primele noțiuni
1.1. Câte ceva despre programe
Bun... Avem totul pregătit, deci să trecem la treabă! :)
Cel mai simplu program afișează ori un text, mai exact un șir de caractere,
ori rezultatul unei operații aritmetice. De exemplu, executând
print("Primul meu program!")
print(7*3+2-10/2)
obținem imediat:
O primă observație ar fi că putem să delimităm, fără a fi însă necesar,
fiecare instrucțiune cu semnul ";", ca mai jos:
print("Primul meu program!");
print(7*3+2-10/2);
Rezultatul este același. Testați!
De asemenea, puteți scrie cele două instrucțiuni pe aceeași linie:
print("Primul meu program!"); print(7*3+2-10/2);
Totuși, limbajul Python este unul orientat puternic spre o redactare care să
permită înțelegerea ușoară a codului altui programator căruia îi parvine
programul, așadar este de preferat ca pe fiecare linie să fie scrisă
o singură instrucțiune.
21
Atenție, dacă scriem
print("Primul meu program!") print(7*3+2-10/2)
vom întâmpina prima eroare:
Pe aceeași linie nu putem scrie două instrucțiuni fără a le separa prin ";",
iar interpretorul Python ne anunță imediat!
Mai mult, Python face diferența dintre literele mari (majuscule) și cele
mici. Testând codul de mai jos:
priNt("Primul meu program!")
obținem:
deci mediul de programare nu recunoaște instrucțiunea "priNt", deoarece
se consideră ca fiind încă nedefinită.
22
Definiția 1.1. Sintaxa limbajului este dată de totalitatea regulilor de scriere
corectă (în sensul acceptării sale de programul traducător (interpretor în
cazul Python), care are rolul de a îl executa. Dar un program corect
din punct de vedere sintactic nu este automat un program bun,
iar corectitudinea sintactică este numai o cerință a programelor, așa cum
vom vedea ulterior.
Definiția 1.2. Prin semantica unui limbaj se înțelege semnificația
construcțiilor sintactice corecte (ce anume realizează instrucțiunile, etc).
Cel mai dificil este ca programul să execute întocmai ceea ce și-a propus cel
care l-a realizat, iar a verifica corectitudinea nu este deloc un lucru simplu.
1.2. Ce sunt variabilele?
Exemplul 1.1. E mai simplu să analizăm inițial programul de mai jos:
x = input()
print(x)
Acest program citește de la tastatură o dată de intrare (un șir de caractere)
prin intermediul funcției input, apoi o afișează cu ajutorul lui print:
Introducem ceva...
Apăsăm tasta Enter...
Ce observăm? Apare în program variabila x care reține data introdusă de la
tastatură (șirul de caractere "hei") la rularea programului.
23
1.2.1. Care este mecanismul prin care se realizează acest lucru?
Calculatorul preia data citită (în acest caz, "hei") şi o depune / reține în
memoria internă. De acolo, aceasta este preluată şi afişată în cadrul
consolei cu ajutorul instrucțiunii print.
Definiția 1.3. Prin citire se înţelege operaţia prin care calculatorul preia o
dată din exterior şi o depune în memoria internă. Pentru citire, mediul
exterior va fi tastatura prin intermediul instrucțiunii input (vom vedea că
există şi alte dispozitive / medii de pe care se poate citi).
Definiția 1.4. Prin scriere se înţelege operaţia prin care calculatorul preia o
dată din memoria internă şi o depune în exterior. Pentru scriere, mediul
exterior va fi pentru moment monitorul / consola (ca şi la citire, vom vedea
că există şi alte dispozitive pe care se poate scrie).
Schema de mai jos sintetizează cele prezentate:
Dată
Citire
Memoria internă a
calculatorului
Dată
Scriere
A spune că o dată este depusă în memoria internă este mult prea puţin.
Memoria internă conţine o mulţime de alte informaţii. Trebuie să ştim locul
(adresa) în care aceasta este depusă. Pentru a putea realiza aceasta, se
foloseşte un procedeu specific. În ce constă el?
Pe scurt, se declară o variabilă (în programul nostru se numeşte x), iar
aceasta are rolul de a reține cele introduse de utilizator. În exemplul
nostru, am introdus numele variabilei, apoi semnul egal și valoarea cu care
am inițializat-o (ceea ce a introdus utilizatorul cu ajutorul funcției input,
mai exact: "hei").
În esență, să ne imaginăm variabila x ca și o "cutiuță" aflată în memoria
internă a calculatorului nostru, unde reținem "hei".
Reprezentarea intuitivă ar fi următoarea:
24
"hei"
x
Dacă am fi citit "wow", am fi avut:
"wow"
x
Revenind, dacă ţinem cont că variabila x se găseşte în memoria internă,
schema devine:
Memoria internă a calculatorului
Dată("hei")
Dată("hei")
Citire
"hei"
Scriere
x
Să observăm că în cazul citirii lui "wow", variabila x reţine "wow", iar în
cazul citirii textului "hei", variabila x reţine "hei". Ne-am imaginat variabila
ca pe o cutiuţă pe care, în cazul nostru, am numit-o x, ce reţine la un
anumit moment o valoare.
Tocmai de aici provine numele de variabilă - deşi are un unic nume x,
reţine diverse date, deci are un conţinut variabil.
1.2.2. Definirea variabilelor în Python
... este extrem de simplă. Alegem un nume potrivit, apoi scriem semnul
egal și introducem valoarea cu care o inițializăm.
Testați codul de mai jos:
n = 123
print(n)
25
Avantajul utilizării limbajului Python este faptul că orice variabilă poate
reține dinamic, pe parcursul unui program, valori de tipuri diferite, fără
a impune tipul la declarare, precum inițializarea în C++.
Continuăm cu un alt caz...
n = 123
print(n)
n = "hei"
print(n)
n = 48
print(n)
Rezultatul este
Ce observăm? Inițial variabila n a reținut valoarea numerică 123, apoi un șir
de caractere "hei", iar la final, din nou o valoare, 48. După fiecare atribuire
am tipărit ceea ce reține variabila n.
Exemplul 1.2. Să analizăm programul de mai jos:
y = input('Numele tau este: ')
print('Salut, ' + y)
Acest program citește de la tastatură un șir de caractere:
Introducem numele...
Apăsăm tasta Enter...
apoi se afișează șirul de caractere format din "Salut, " și numele introdus:
26
Observații
1. Un șir de caractere poate fi format din mai multe cuvinte:
2. În exemplul al doilea:
funcția input are între paranteze un text care este afișat atunci
când trebuie să introducem datele de la tastatură; acesta apare
în linia de comandă / consolă și ne oferă un indiciu asupra a
ceea ce trebuie să scriem ("Numele tau este: ");
am introdus special un spațiu după caracterul ":" mai sus a.î. la
rularea programului să respectăm spațierea convențională
(implicit, cursorul rămâne imediat după textul ales ca indiciu);
în cadrul instrucțiunii (funcției) print am folosit operatorul "+"
care concatenează (alătură) cele două șiruri de caractere:
"Salut, " + "Vlad"
"Salut, Vlad"
(veți învăța detaliat aceste noțiuni puțin mai târziu)
Exemplul 1.3. Fără alte comentarii, analizați și rulați programul:
print("Salutare, draga vizitator!")
print("-------------------------- ")
x = input('Numele tau este: ')
y = input('Prenumele tau este: ')
print("-------------------------- ")
print('Bine ai venit, ' + x + " " + y + "!")
În cazul meu, am obținut în consolă ca mai jos:
27
Super, nu?
Observăm un alt aspect important.
Când funcția input este executată, programul se oprește și așteaptă date
de la utilizator / tastatură, deci până la apăsarea tastei Enter, totul este
în așteptare.
1.2.3. Hei!.. 2 + 3 nu fac 23!?!
Da, aparent pare ciudat. Să presupunem că avem următorul program:
x = input("x=")
y = input("y=")
print(x+y)
Răspunsul este simplu. Funcția input oferă implicit ca șir de caractere orice
informație introdusă, iar operatorul "+" pur și simplu a alăturat cele două
caractere și le-a afișat în consolă, deci tipul de date reținut este esențial.
Pentru a le folosi corect, datele trebuie convertite după caz!
Veți învăța în curând tipurile de date și modul de
a le converti corespunzător.
28
1.3. Vocabularul limbajului
Vocabularul oricărui limbaj de programare este format din:
setul de caractere;
identificatori;
separatori;
comentarii.
1.3.1. Setul de caractere
Setul de caractere reprezintă ansamblul de caractere cu ajutorul cărora se
poate realiza un program în Python, iar acesta este alcătuit din:
litere mari și mici ale alfabetului englez (A-Z, a-z);
cifrele sistemului de numerație în baza 10 (0-9);
caractere speciale (+, -, *, /, =, ^, <, >, (, ), , , {, }, ., ,, :, ;, #, $, @, _,
și blank (spațiu)).
Spre deosebire de alte limbaje de programare, versiunea Python 3 ne oferă
direct reprezentarea caracterelor folosind standardul Unicode, mai exact în
formatul UTF-8. Deci, putem introduce și caractere care nu sunt bineînțeles
pe tastatură, ci le putem prelua de pe Internet căutând lista UTF-8.
Exemplul 1.4. Copiați codul de mai jos și executați-l:
grecesc = "αβγδεζηθικλμνξοπρςστυφχψ"
print(grecesc)
print("î ă â ş ţ")
De notat faptul că primele 128 de caractere din lista celor UTF-8 sunt cele
care se găsesc în formatul ASCII, utilizat de alte medii de programare
(vezi Anexa 2. Tabela codurilor ASCII).
29
1.3.2. Identificatori
Prin identificatori vom înțelege o succesiune de litere, cifre sau caracterul
special "_", cu condiția ca prima să nu fie cifră. Cu ajutorul identificatorilor
se asociază nume constantelor, variabilelor, funcțiilor, etc.
Exemplul 1.5. Priviți declarările variabilelor următoare:
var1 = "mama"
var2 = "tata"
un_sir = "o familie"
Ca și contraexemple, avem "1var", "sir&".
primul începe cu o cifră, iar al doilea
conține un caracter special.
O categorie deosebită de identificatori este dată de cuvintele cheie ale
limbajului Python (au un înțeles bine definit și nu pot fi folosite în alt
context). Lista completă este cea de mai jos:
False
None
True
and
as
assert
async
await
break
class
continue
def
del
elif
else
except
finally
for
from
global
if
import
in
is
lambda
nonlocal
not
or
pass
raise
return
try
while
with
yield
iar acestea trebuie scrise exact ca mai sus pentru a fi interpretate corect.
1.3.3. Separatori
Definiția 1.5. Cele mai simple elemente alcătuite din caractere cu semnificație lingvistică poartă denumirea de unități lexicale.
Acestea se separă între ele, după caz, prin unul sau mai multe spații,
caracterul de sfârșit de linie sau caracterul ";", așa cum ați văzut deja.
Exemplul 1.6. ab semnifică poate numele unei variabile, așadar avem o
unitate lexicală, pe când a b conține două unități...
30
1.3.4. Comentarii
Python încurajează introducerea comentariilor în codul nostru, deoarece
este mult mai ușor de înțeles ulterior. Acestea se pot introduce oriunde în
program, încep cu caracterul diez ("#") și continuă până la sfârșitul liniei.
Exemplul 1.7. Mai jos avem un program care conține comentarii:
Ele sunt ignorate la rularea (interpretarea) programului.
1.4. Tipuri de date
Ați văzut faptul că o variabilă poate reține la un moment dat un anumit tip
de date în Python – ori un număr, ori un șir de caractere (text) până acum.
De asemenea, o primă problemă am identificat-o atunci când ne-am dorit
să adunăm două numere introduse de la tastatură.
Implicit, funcția input preia informația din consolă și o oferă sub forma de
șir de caractere spre manipulare în codul nostru.
Pornim de la acest studiu de caz:
n = input("n=")
m = input("m=")
print(n + m)
Dacă introducem "Star" și "Wars", rezulatul va fi obținut prin alăturarea /
concatenarea celor două cuvinte, respectiv "StarWars". Dacă introducem
"5" și "6", rezultatul va fi similar, "56".
Să vedem cum putem impune tipul de date dorit...
31
Atunci când definim o variabilă, alocăm de fapt un spațiu în memoria
internă a.î. să putem reține în acea locație valoarea impusă de noi.
În Python nu este necesar să declarăm explicit tipul la inițializare, cum este
cazul altor limbaje de programare, ca Pascal ori C++.
În Python există cinci tipuri standard de date principale:
1.
2.
3.
4.
5.
Numerice
Șiruri de caractere
Liste
Colecții de date
Tupluri
(acestea au asociat un capitol separat)
Dicționare
1.4.1. Tipuri de date numerice
Tipurile de date numerice sunt int (numere întregi cu semn), float (numere
reale, cu zecimale) și complex (numere complexe). Exemple:
int
float
complex
11
0.0
2+3j
124
23.14
1-2j
-93
-173.955
3.14j
La definirea unei variabile, putem folosi funcția cu numele respectiv a.î. să
impunem tipul de date ce va fi reținut.
Exemplul 1.8. Revenind la studiul
de caz, scriem:
n = int(input("n="))
m = int(input("m="))
print(n + m)
Am folosit funcția int() care a primit ca parametru șirul de text introdus de
utilizator. Aceasta l-a convertit spre o valoare întreagă cu semn ce a fost
reținută de variabila n, apoi similar de m. De această dată rezultatul este
unul corect matematic și asta ne doream – adunarea numerelor.
32
Observație. Deoarece am impus ca tip de date int pentru cele două
variabile, n și m, dacă încercăm să introducem textul Star (sau "Star" ori
'Star') ca valoare pentru prima variabilă, vom obține eroare:
pentru că n nu poate reține acum decât numere întregi cu semn (funcția
int nu poate primi ca parametru un șir de caractere, evident).
Exemplul 1.9. Un număr real (float), adunat cu un număr întreg (int), obține
un rezultat real (float):
n = float(input("n="))
m = int(input("m="))
print(n + m)
Pentru 5 și 6, obținem 11.0.
Pentru 5.23 și 2, obținem 7.23.
Pentru 2.128 și 4, obținem 6.128.
Observăm că implicit rezultatul se rotunjește cu numărul de zecimale al
celui mai detaliat număr real. Dacă introducem un număr întreg, este
folosită o singură zecimală, 0, care ne indică tipul de date – float.
Exemplul 1.10. Pentru a declara un număr complex, introducem partea
reală (5.12) și partea imaginară (-3) ca argumente:
În acest caz am lucrat direct în consolă.
33
Exemplul 1.11. Folosind funcțiile, mai exact constructorii (veți înțelege
noțiunea când studiați Programarea Orientată pe Obiecte), int, float și
complex fără vreun parametru/argument, obținem implicit zero:
1.4.2. Șiruri de caractere
Am folosit deja șirurile de caractere, care în engleză se numesc string.
De fapt, se inițializează o variabilă ce reține un șir de caractere,
iar conversia explicită spre acest tip se efectuează prin funcția str().
Exemplul 1.12. Priviți instrucțiunile de mai jos, introduse în consolă:
Observații
În Python, un string repezintă un șir de caractere continuu, delimitat
de apostrofuri sau ghilimele, ca mai sus.
Așa cum am văzut și anterior, un șir de caractere se poate defini
direct, fără a fi necesară funcția str(), ca în cazul variabilei str3.
34
Exemplul 1.13. Putem introduce șiruri de caractere care se află pe mai
multe linii. În acest caz folosim trei apostrofuri:
1.4.3. Date numerice vs. șiruri de caractere
Folosind funcția de intrare input, obținem datele sub forma unui șir de
caractere. Limbajul Python este intuitiv însă la atribuirea valorilor unei
variabile, precum mai jos:
Bineînțeles că dacă încercăm să adunăm v1 cu v2, rezultatul va fi 30.3, deci
de tip float, iar în cazul v1 cu v3, obținem eroare – nu putem aduna un
număr întreg cu un șir de caractere...
35
1.5. Mai multe moduri de atribuire
Așa cum a fost prezentat, putem scrie
var1 = 23
sau explicit
var1 = int(23)
iar variabila var1 reține apoi un număr întreg cu semn, mai exact 23.
Putem efectua însă o atribuire multiplă, ca mai jos:
var1 = var2 = var3 = 1
Cele 3 variabile vor reține numărul întreg 1.
Sau un alt exemplu:
Testați!
Astfel, v1 reține valoarea întreagă 2, v2 reține numărul real 5.0,
iar v3, șirul de caractere "sir".
De asemenea, putem citi mai multe variabile pe un singur rând:
36
1.6. Funcția type
Oricând putem afla tipul de date reținut de o anumită variabilă la un
anumit moment dat folosind funcția type.
Exemplul 1.14. Analizați programul următor:
Funcția type primește în acest caz ca parametru variabila x (de fapt, un
obiect) și întoarce ca și rezultat clasa acestuia - în cazul nostru, tipul
de date reținut.
1.7. Operaţii aritmetice elementare introductive
Adunarea. Pornim de la exemplul prezentat anterior, adunarea a două
numere întregi cu semn, valori introduse de la tastatură, program
prezentat mai jos:
x = int(input())
y = int(input())
print(x+y)
El calculează suma între numerele 5 şi 6. Ca şi la matematică, pentru
adunare se foloseşte semnul "+". Observaţi cum am procedat: am scris pur
şi simplu în interiorul instrucțiunii (funcţiei) print expresia x+y. Mediul de
programare va face suma şi va afișa rezultatul apoi în consolă.
Astfel putem calcula suma mai multor numere naturale. În programul de
mai jos se calculează suma a 3 numere naturale:
print(23+12+7)
37
Bineînțeles, putem folosi 3 variabile a.î. să realizăm un program ce oferă
posibilitatea utilizatorului să adune oricare 3 numere întregi cu semn
(am folosit la conversie funcția int din nou):
x = int(input())
y = int(input())
z = int(input())
print(x+y+z)
Puteam scrie însă și așa...
x = input()
y = input()
z = input()
print(int(x)+int(y)+int(z))
Conversia o putem realiza și la afișare, pentru fiecare variabilă în parte.
Scăderea. Aşa cum pentru adunare folosim semnul "+", pentru scădere se
foloseşte semnul "-", întocmai ca la matematică. Programul de mai jos
calculează diferenţa dintre numerele 79 şi 53:
print(79-53)
ori altul care primește valorile de la tastatură (de exemplu, numere reale):
x = float(input())
y = float(input())
print(x-y)
Produsul. Putem calcula şi produsul a unor numere. Spre deosebire de
matematică, pentru înmulţire vom folosi semnul "*" (asterisc):
x = int(input())
y = int(input())
z = int(input())
print(x*y*z)
Evident, puteți introduce și numere
întregi negative, testați!
38
Împărțirea întreagă. Cum facem împărţirea a două numere naturale?
De la început, precizăm că este vorba de împărţirea întreagă. Ce înţelegem
prin împărţirea întreagă? Fiind dat deîmpărţitul şi împărţitorul, trebuie să
aflăm un număr întreg care să ne spună de câte ori intră împărţitorul
în deîmpărţit.
Exemplu: deîmpărţitul este 25, iar împărţitorul 10. Câtul va fi 2 (pentru că
10 intră de două ori în 25).
Dacă notăm deîmpărţitul cu D, împărţitorul cu I, câtul cu C, iar restul cu R,
între ele există identitatea fundamentală:
D=IC+R, unde R0, R<I
Pentru calculul restului vom folosi relaţia: R=D-IC. Astfel, pentru a calcula
restul împărţirii lui 25 la 10 vom calcula R=25-210=5.
În Python, pentru a calcula câtul a două numere naturale se foloseşte
operatorul "//". Astfel, pentru a calcula câtul întreg dintre 25 şi 10 vom
scrie 25 // 10. Pentru calculul restului există operatorul (modulo) "%".
Pentru a calcula restul împărţirii numărului 25 la 10 vom scrie 25 % 10.
Paranteze. Putem calcula şi expresii care conţin paranteze. După cum ştim
de la matematică, parantezele schimbă prioritatea operaţiilor. De exemplu,
3(4+2)=18. Programul este cel de mai jos:
Tipul rezultatului în acest caz este int deoarece expresia 3(4+2) conține
doar valori de tip întreg.
39
Putem calcula şi expresii care conţin paranteze imbricate. Spre deosebire
de matematică, în Python nu putem folosi decât paranteze rotunde. Astfel,
în loc să scriem 2+3(2+1)2, vom scrie (2+3*(2+1))*2. Ce va tipări
programul de mai jos?
Atenție, la matematică putem scrie 3(4+2), însă în Python avem nevoie de
operatorul de înmuțire, adică 3*(4+2).
Împărțirea reală. Operatorul care efectuează această operație este "/".
În cazul lui Python 3, rezultatul operației de împărțire este de tip float,
chiar dacă avem ca operanzi numere întregi, nu doar reale.
Exemplul 1.15. Analizați programul următor:
În primele două cazuri a fost efectuată împărțirea unui număr întreg cu
semn (de tip int) la 2, iar rezultatul a fost de tip float. Următoarele două au
ca operanzi două numere reale, 7.0, respectiv -7.0, iar rezultatul este
evident unul real. Ultimele nu mai necesită alte comentarii.
Observați dinamica și adaptivitatea limbajului de programare Python.
40
1.8. Ce este un algoritm?
Vom porni de la un exemplu preluat din viaţa noastră. Să presupunem că
mama ne roagă următorul lucru:
Ce trebuie să facem? Când am decis să plecăm după pâine, vom
proceda astfel:
luăm banii necesari;
ne îndreptăm către magazin;
solicităm o pâine;
o plătim;
o luăm;
venim cu ea către casă;
o dăm mamei.
Dacă ar fi să sintetizăm acestea, am obţine şirul acţiunilor ce urmează
a fi executate ca să cumpărăm pâinea:
început
ia banii;
deplasează-te la magazin;
cere o pâine;
plăteşte pâinea;
ia pâinea;
deplasează-te cu pâinea acasă;
predă pâinea;
sfârşit
Vom conveni ca ultima înșiruire de pași să o numim algoritm de cumpărare
pâine. Astfel, orice copil care cumpără o pâine va executa acţiunile
conţinute de acest algoritm.
41
Totuşi ... ce este un algoritm? Ni-l putem imagina ca un şir de acţiuni în
vederea atingerii unui obiectiv. Cu toate acestea, o definiţie precisă a
noţiunii de algoritm nu poate fi oferită.
Să observăm că acţiunile care alcătuiesc algoritmul se execută în ordinea în
care au fost introduse. Altfel, degeaba plecăm să cumpărăm pâine dacă nu
am luat banii, n-am cui să cer o pâine dacă nu am ajuns la magazin, etc.
Gândiți-vă și voi la alte exemple din viața de zi cu zi care se pot transpune
sub forma unui algoritm!
Un program cuantifică un algoritm Robotul cumpără pâinea: execută
orbeşte un şir de acţiuni (pentru calculator acestea se numesc instrucţiuni).
Pentru a putea cumpăra pâinea, robotul trebuie învăţat (să cunoască
deci algoritmul).
Redactarea algoritmilor direct într-un limbaj de programare (obţinând
imediat programul) este avantajoasă prin faptul că putem verifica dacă
algoritmul este corect prin rularea programului (hârtia suportă orice
prostie, calculatorul însă nu). Cu toate acestea, prin faptul că, la redactare,
trebuie ţinut în permanenţă cont de restricţiile limbajului, putem greşi.
Indiferent de forma de redactare, esenţial este ca un algoritm să fie gândit
corect, iar asta nu este uşor!
42
Robotul se blochează - nu a fost instruit pentru un astfel de eveniment
neprogramat anterior. Un om poate lua o decizie (de exemplu, să plece la
alt magazin), dar robotul nu ia decizii dacă nu a fost învăţat. Apare o
situaţie pe care algoritmul nu o conţine...
Exact aşa se întâmplă şi cu un calculator care execută un program
insuficient gândit. Programul se va termina cu eroare, pentru că nu am
prevăzut acest caz! Concluzia?
Un algoritm corect elaborat trebuie să prevadă toate situaţiile posibile!
Rețineți: nu este greu să învăţăm un limbaj de programare, însă este mult
mai greu să învăţăm să elaborăm algoritmi corecţi!
Probleme propuse / Exerciții
1. Ce înţelegeţi prin noţiunea de algoritm?
2. Ce înţelegeţi prin noţiunea de variabilă?
3. În viaţa de toate zilele întâlnim la tot pasul algoritmi, ca de exemplu:
algoritmul prin care dăm un telefon, algoritmul de adunare a două
numere întregi, etc. Daţi şi voi alte exemple de algoritmi!
43
4. Completaţi câmpurile de mai jos astfel încât să obţineţi ordinea corectă a
şirului de acţiuni care formează algoritmul numit, să-i spunem, Căutare:
Citesc informaţiile afişate în urma căutării;
Introduc cuvintele cheie pentru căutare;
Deschid calculatorul;
Sfârşit
Introduc adresa http://www.google.ro;
Început
Accesez una dintre paginile afişate de Google;
Apelez un browser web;
5. Folosind algoritmul de mai sus, documentaţi-vă pe Internet despre omul
de ştiinţă Abu Abdullah Muhammad bin Musa al-Khwarizmi1!
6. Scrieţi un program care citeşte un număr natural şi tipăreşte produsul
dintre acesta şi numărul 5.
7. Scrieţi un program care calculează produsul a două numere reale citite.
8. Scrieţi un program care calculează câtul întreg şi restul a două numere
citite din consolă.
9. Scrieţi un program care citeşte două numere naturale şi tipăreşte suma,
diferenţa, produsul şi câtul lor întreg.
10. Scrieţi un program care tipăreşte tabla înmulţirii cu un număr natural
între 2 şi 9 (numărul va fi citit de la tastatură).
1
Noţiunea de algoritm are la origine numele acestui savant persan, care a fost astronom,
astrolog, matematician şi scriitor.
44
11. Scrieţi un program care citeşte un număr natural n şi afişează pe
câte o linie:
n la puterea a doua;
n la puterea a treia.
12. Se citesc două numere cifre nenule și distincte. Afișați cele două
numere care pot fi formate cu acestea. Pentru 3 și 5, se va afișa 35 și 53.
12. Scrieți un program care afișează desenul de mai jos, folosind doar
caracterele "@", "*", "\", "/", "_" și spațiul.
13. Scrieți un program care afișează datele voastre personale sub forma
unei cărți de vizită, precum a mea – fiți inventivi!
Scrieți-vă și adresa de email...
14*. Istorie. Realizaţi un program care să precizeze epocile istorice în
funcţie de perioadă, fiecare pe câte o linie (epoca străveche, epoca antică,
epoca medievală, epoca modernă şi epoca contemporană).
15*. Geografie (Astronomie). Realizaţi un program care să descrie pe scurt
sistemul nostru solar. Precizaţi, pe câte o linie, numele celor 8 planete care
se învârt în jurul Soarelui. Eventual, pentru fiecare scrieţi alăturat
(pe aceeaşi linie) câte un satelit ori dimensiunea!
45
Expresii
Pentru a efectua calcule, programele folosesc expresii. Până în acest
moment le-am întâlnit de mai multe ori. În acest capitol ne propunem un
studiu sistematic al expresiilor şi o bună înţelegere a acestora ne scuteşte
de multe erori pe care le-am putea face.
2.1. Introducere
Definiția 2.1. Se numește expresie o succesiune alcătuită din unul sau mai
mulţi operanzi, legaţi între ei prin operatori, conform unor reguli sintactice
specifice limbajului de programare.
(3, 4 și 2 sunt operanzi, iar + și *, operatori)
O expresie scrisă incorect va conduce la apariţia unei erori la interpretare
(aceasta se numeşte eroare de sintaxă).
(lipseşte operatorul de înmulţire - nu este implicit ca la matematică)
Rescriem programul și vom avea afișat rezultatul corect:
În timpul executării programului Python, expresiile sunt evaluate (adică se
calculează un rezultat).
Analizați și următoarele expresii sintactic corecte.
46
1) 3+2
2) 4.5+1*8
3) a+3*(b+2), unde a şi b sunt variabile de tip întreg cu semn (a=1, b=3)
4) a>b, unde a este o variabilă întreagă (a=3), iar b una reală (b=1.2)
Exemple de operanzi în expresiile anterioare: 3, 2, 4.5, a, b.
Exemple de operatori în expresiile anterioare: +, *, >.
În urma evaluării expresiei 1) se obţine valoarea întreagă 5 (tipul int).
În urma evaluării expresiei 2) se obţine valoarea reală 12.5 (tipul float).
Pentru evaluarea expresiei 3) se înlocuieşte valoarea lui a cu 1 şi valoarea
lui b cu 2. Se obţine: 1+3*(3+2)=16 (tipul int).
În urma evaluării expresiei 4) se obţine valoarea logică True (adevărat),
pentru că 3 este mai mare ca 1.2.
PROPRIETĂȚI
Esențial este să înțelegeți modul în care se evaluează o expresie, iar pentru
aceasta avem nevoie de anumite noțiuni fundamentale.
Prioritatea (precedența) operatorilor. Deja sunteți obișnuiți cu această
noțiune, știind că indică ordinea efectuării operațiilor.
Asociativitatea operatorilor. Noțiunea este nouă, find de două feluri: de la
stânga la dreapta și de la dreapta la stânga. De la început precizăm că
operatorii cu aceeași prioritate au aceeași asociativitate.
Pentru a înțelege noțiunea de asociativitate, pornim de la o expresie în
care operanzii sunt legați prin operatori cu aceeași prioritate. Dacă asociativitatea operatorilor este de la stânga spre dreapta, prima operație care se
efectuează este cea corespunzătoare primului operator din stânga, a doua
operație este cea corespunzătoare celui de-al doilea din stânga, etc.
Evident, în cazul în care asociativitatea este de la dreapta la stânga, prima
operație care se efectuează este cea a operatorului din dreapta, ș.a.m.d.
47
Spre exemplu, dacă avem operația 7 * 2 // 4, avem asociativitatea de la
stânga la dreapta, deci se efectuează mai întâi 7*2, apoi 14//4, rezultatul
fiind evident 3. Așadar, operatorii au aceeași prioritate.
Pe de altă parte, cu ajutorul operatorului "**", puteți ridica un număr la
puterea unui exponent. În acest caz, asociativitatea este de la dreapta
la stânga, precum mai jos:
Mai întâi, a fost efectuată operația 32, rezultatul fiind 9. Apoi, 29 care
obține valoarea 512.
Observați că 2 ** 3 ** 2 este echivalent cu 2 ** (3 ** 2).
Dacă folosim parantezele, rezultatul diferă, bineînțeles, deoarece acestea
au o prioritate superioară operatorului "**":
În acest caz se efectuează mai întâi paranteza, adică 23 = 8, apoi 82,
rezultatul final fiind 64.
Non-asociativitate. Nu toți operatorii dețin această proprietate, precum
semnele mai mic "<" și mai mare ">". De exemplu, x < y < z semnifică x < y
și y < z, nicidecum x < (y < z) și este evaluată de la stânga la dreapta.
Rețineți că atunci când scrieți expresii, rezultatul depinde de mediul
de programare utilizat, în acest caz Python, versiunea 3, precum și de
totalitatea regulilor de sintaxă și a proprietăților cu ajutorul cărora acestea
sunt evaluate.
Atenție! Scriem a*, dar lipsește al doilea operand. Cu cine îl înmulțim?
Vom avea iar eroare de sintaxă...
În continuare sunt prezentați operatorii în Python.
48
2.2. Operatori în Python
Limbajul Python este dotat cu un set puternic de operatori și ca în
prezentarea acestora să nu facem apel tot timpul la prioritatea lor, precum
și modul în care aceștia se asociază, considerăm tabelul de mai jos:
Prioritate
Operatori
Asociativitate
1
()
S --> D
2
**
D --> S
3
+x, -x, ~x
S --> D
4
*, /, //, %
S --> D
5
+, -
S --> D
6
<<, >>
S --> D
7
&
S --> D
8
^
S --> D
9
|
S --> D
10
==, !=, >, >=, <, <=, is, is not, in, not in
S --> D
11
not
S --> D
12
and
S --> D
13
or
S --> D
Tabelul 2.1. Operatori în Python
49
2.2.1. Operatori aritmetici
Operatorii aritmetici sunt de două feluri:
operatori unari (+, - și ~);
operatori binari ( +, -, *, /, //, %).
Operatorii unari acţionează asupra unui singur operand, care poate fi
o variabilă de tip numeric. Operandul se găseşte întotdeauna în dreapta
operatorului. Nu are sens ca aceştia să fie aplicaţi variabilelor de tip str sau
bool (ce rețin doar True sau False).
Exemple: fie a o variabilă întreagă care conţine numărul 2. Atunci:
-a va avea ca rezultat -2;
--a va avea ca rezultat 2;
+a va avea ca rezultat 2;
-+a va avea ca rezultat -2.
Analog, dacă a este o variabilă reală (de tip float), ori complexă (complex).
Exemplu de eroare: a este o variabilă de tip șir de caractere (str) care
conţine "o". Atunci -a nu are sens, întrucât operatorii unari nu acţionează
asupra variabilelor de tip str:
Operatorii binari acţionează asupra a doi operanzi. Un operand se găseşte
întotdeauna în stânga operatorului, iar celălalt în dreapta sa.
Aceştia sunt: +, -, *, /, //, %.
Operatorul + are semnificaţia de adunare. Operanzii săi sunt de tip întreg
cu semn sau real. Se poate ca unul să fie de tip întreg şi celălalt de tip real.
50
Exemplu. Dacă cel puţin unul din operanzi este de tip
real (float), rezultatul este de tip real, altfel este de
tip întreg cu semn (int).
Observaţie. Operatorul + apare şi ca operator unar.
De asemenea, apare ca sumă de şiruri (caz pe care
nu-l discutăm acum, însă ați văzut că se pot alătura (concatena) două sau
mai multe șiruri de caractere folosindu-l).
Operatorul – are semnificaţia de scădere. Operanzii sunt de tip întreg cu
semn sau real (ori complex). Dacă cel puţin un operand este real, rezultatul
este de tip real, altfel este de tip întreg.
Exemple:
3-2 are ca rezultat valoarea întreagă 1
2-3 are ca rezultat valoarea întreagă -1
c este o variabilă de tip real care conţine valoarea 2.3. Atunci c-1
va avea valoarea de tip real 1.3
c este o variabilă de tip real care reţine
numărul 1 (de fapt 1.0). Atunci c+1 va fi 2
(de fapt 2.0, precum vedeți alăturat).
Operatorul * are semnificaţia de înmulţire. Operanzii sunt de tip întreg sau
real. Dacă cel puţin unul din operanzi este de tip real, rezultatul este de
tip real, altfel rezultatul este de tip întreg.
Exemple:
3*2 are ca rezultat valoarea întreagă 6
3.5 *2 are ca rezultat valoarea reală 7.0
a este o variabilă reală care reţine 2. Atunci a*2 are ca rezultat
valoarea reală 4 (adică, 4.0).
Operatorul / are semnificaţia de împărţire. Operanzii pot fi de tip întreg
sau real, dar, întotdeauna rezultatul este de tip real.
Exemple:
3/2 are ca rezultat valoarea reală 1.5
4/2 are ca rezultat valoarea reală 2.0
51
a este o variabilă reală care reţine numărul 1.5, iar b este o
variabilă reală care reţine numărul 0.75. Atunci a/b are ca rezultat
valoarea reală 2.0.
Operatorul // (cunoscut în alte limbaje ca div) are semnificaţia de
împărţire întreagă (în engleză, floor division, deoarece rezultatul împărțirii
se rotunjește în jos spre un număr întreg) – a mai fost prezentat
în Capitolul 1.
Exemple. Rezultatul este un număr întreg în fiecare caz:
7//2, se obține 3
14//2, se obține 7
25//12, se obține 2
Rezultatul împărțirii întregi în Python 3 este un număr real (float) doar dacă
unui dintre operanzi este de asemenea număr real, ca mai jos:
10//3.0, se obține 3.0, deci de tip float
De asemenea, pentru operanzi negativi, avem rezultate precum:
-10//3, se obține -4 (tipul int)
deoarece -4 < -3.3333 < -3. Atenție în acest caz, teorema împărțirii cu rest
D=ÎxC+R poate fi folosită, iar restul este 2 (-10 = 3*(-4) + 2) !
Totuși, este de preferat să folosiți ca operanzi numere întregi pozitive...
Operatorul % (cunoscut ca modulo) are semnificaţia de rest al împărţirii
pentru numere întregi – de asemenea, deja prezentat.
Exemple. Rezultatul este un număr întreg în fiecare caz:
7%2, se obține 1
14%2, se obține 0
25%12, se obține 1
Atenție din nou, pentru operanzi negativi, ca în cazul -10%3, se obține 2,
iar în cazul operanzilor reali, se complică lucrurile:
25%2.2 = 0.799999999999998. De ce? Păi... 25 = 2.2*11+0.8.
52
2.2.2. Operatori relaționali
Toţi operatorii relaţionali sunt binari (acţionează asupra a doi operanzi).
Aceştia sunt: > (mai mare), >= (mai mare sau egal), < (mai mic), <= (mai mic
sau egal), == (egal) şi != (diferit).
Operanzii pot fi variabile sau valori de orice tip învăţat. În acest capitol
vom studia modul de acţiune al operatorilor relaţionali numai asupra
variabilelor întregi sau reale.
Rezultatul aplicării unui operator relaţional este întotdeauna o valoare
logică - True (adevărat) sau False (fals).
Deoarece Python face diferența între literele mari și literele mici, atenție
la majuscule!
Operatorul < (mai mic). Fiind daţi doi operanzi a şi b, operatorul < arată
dacă este adevarată sau nu relaţia a<b. Dacă relaţia este adevărată
rezultatul va fi True, altfel rezultatul va fi False.
Exemple:
2<3, rezultat True
3<3 rezultat False
2.1<5 rezultat True
a<b, unde a este o variabilă reală care conţine valoarea 5.9, iar b
o variabilă reală care conţine 2.3, rezultat False
Operatorul <= (mai mic sau egal). Fiind daţi doi operanzi a şi b, operatorul
<= arată dacă este adevărată sau nu relaţia a<=b. Dacă relaţia este
adevărată rezultatul va fi True, altfel rezultatul va fi False.
53
Exemple:
2<=3, rezultat True
3<=3, rezultat True
5.1<=5, rezultat False
a<=b, unde a este o variabilă reală care conţine valoarea 5.9, iar b
o variabilă reală care conţine 2.3, rezultat False
Operatorul > (mai mare). Fiind daţi doi operanzi a şi b, operatorul > arată
dacă este adevărată sau nu relaţia a>b. Dacă relaţia este adevărată
rezultatul va fi True, altfel rezultatul va fi False.
Exemple:
2>3, rezultat False
3>3 rezultat False
7.1>5 rezultat True
a>b, unde a este o variabilă reală care conţine valoarea 5.9, iar b o
variabilă reală care conţine 2.3, rezultat True
Operatorul >= (mai mare sau egal). Fiind daţi doi operanzi a şi b, operatorul
>= arată dacă este adevărată sau nu relaţia a>=b. Dacă relaţia este
adevărată rezultatul va fi true, altfel rezultatul va fi False.
Exemple:
2>=3, rezultat False
3>=3 rezultat True
5.1>=5 rezultat True
a>=b, unde a este o variabilă reală care conţine valoarea 5.9, iar b
o variabilă reală care conţine 6, rezultat False
Operatorul == (egal). Fiind daţi doi operanzi a şi b, operatorul == arată dacă
este adevarată sau nu relaţia a==b. Dacă relaţia este adevărată rezultatul
va fi True, altfel rezultatul va fi False.
Exemple:
2==3, rezultat False
3==3 rezultat True
2.1==5 rezultat False
54
Operatorul != (diferit). Fiind daţi doi operanzi a şi b, operatorul != arată
dacă este adevarată sau nu relaţia a!=b. Dacă relaţia este adevărată
rezultatul va fi True, altfel rezultatul va fi False.
Exemple:
2!=3, rezultat True
4+7 != 10+1 rezultat False
Observați prioritatea operatorilor! Mai întâi au fost evaluate calculele
matematice, apoi comparația între cele două valori rezultate (11 != 11).
2.2.3. Operatori logici
Operatorii logici sunt următorii: not (negare), and (şi), or (sau).
Cu excepţia operatorului not - care este unar (acţionează asupra unui
singur operand), restul operatorilor logici sunt binari (acţionează asupra a
doi operanzi). Operanzii pot fi de tip logic, întreg, real, etc. Rezultatul va fi
întotdeauna o valoare de tip logic – True sau False.
Operatorul de negare logică (not) acționează astfel: dacă operandul
este o valoare diferită de 0 ori True, rezultatul este False; în oricare alt caz,
rezultatul este True.
Exemple (executate în consolă):
not False afișează True
not 3>7 afișează True (deoarece 3>7 este False)
not 81 afișează False
not 0 afișează True
Operatorul și logic (and). Modul de obţinere al rezultatului se poate
observa din tabelul de mai jos:
and
True
False
True
True
False
False
False
False
Dacă ambii operanzi sunt diferiți de False, rezultatul este True;
altfel este False.
55
Evident, în locul valorilor True sau False se pot folosi variabile de tip logic
sau alte expresii.
Exemplul 1. var1 este o variabilă logică care conţine True, iar var2 este o
variabilă logică care conţine False. Avem var1 and var2 = False.
Exemplul 2. var1 este o variabilă logică care conţine False, iar var2 este o
variabilă logică care conține 7*3 >= 20. Avem var1 and var2 = False.
Exemplul 3. var1 este o variabilă logică care reține 4>3, iar var2 este o
variabilă logică care conţine True. Avem var1 and var2 = True.
Exemplul 4. var1 este o variabilă logică care reține not 2, iar var2 este o
variabilă logică care conţine True. Avem var1 and var2 = False.
56
Operatorul sau logic (or). Modul de obţinere a rezultatului se poate
observa din tabelul de mai jos:
or
True
False
True
True
True
False
True
False
Și aici regula este simplă: dacă unul dintre operanzi este True, rezultatul
este True, altfel rezultatul este False.
2.2.4. Valori booleene
Precum vedeți, o importanță deosebită o au valorile de
adevăr True sau False. Acestea se numesc valori booleene,
iar conceptul a fost definit prima dată de un matematician
din secolul al XIX-lea, numit George Boole.
Veți înțelege pe parcurs că aceste valori sunt esențiale în
deciziile pe care un program trebuie să le ia în funcție de
valorile introduse de utilizator ori determinate în cod:
True
False
expresie
Dacă e adevărat,
se întâmplă ceva...
Dacă nu e adevărat,
se întâmplă altceva...
Precum funcțiile care convertesc explicit spre un tip de date, așa și
bool(argument)
întoarce o valoare de adevăr (True sau False) în urma evaluării expresiei
care este trimisă ca argument.
Să vedem câteva exemple...
57
Exemplul 1. Se citește de la tastatură un număr. Dacă este mai mare sau
egal cu zero, se afișează True, altfel, False:
n = int(input("Introduceti un numar: "))
print(n>=0)
În variabila n se reține un număr întreg cu semn citit. La afișare, se
tipărește valoarea de adevăr a comparației (expresiei) n>=0.
Exemplul 2. Se citește de la tastatură un număr. Se afișează dacă este sau
nu diferit de zero:
n = bool(int(input("Introduceti un numar: ")))
print("Este diferit de zero? Raspuns:")
print(n)
Funcția input citește un șir de caractere în esență, adică numărul introdus.
Acesta este convertit explicit spre tipul întreg cu semn de funcția int.
Aceasta se găsește ca argument al funcției bool, ce oferă ca rezultat o
valoare True (diferit de zero) sau False (egal cu zero). Interesant...
58
Exemplul 3. Am rulat în consolă următoarele instrucțiuni:
Observați valorile de adevăr în urma evaluării argumentului funcției de
conversie bool.
Tipul de date reținut de o variabilă după atribuire este bool:
2.2.5. Operatori de atribuire
Am folosit până acum atribuirea ca un operator, oferind o anumită valoare
unei variabile. Așadar, forma generală este
v = expresie
În acest caz, v este variabila.
Principiul de executare este următorul:
se evaluează expresia;
variabilei v i se atribuie valoarea obținută.
59
De asemenea, se pot efectua atribuiri multiple de forma:
v = v1 = v2 = ... = vn = expresie
unde v, v1, v2, ..., vn sunt variabile.
În acest caz, principiul de executare este următorul. Se evaluează întâi
expresia. Valoarea obținută este atribuită variabilei vn. Conținutul variabilei
vn este atribuit variabilei vn-1, ..., iar variabila v va reține conținutul lui v1.
După cum vedeți, operatorul de atribuire are asociativitatea de la dreapta
la stânga.
Pentru atribuiri, se mai pot utiliza și următorii operatori:
Operator
Exemplu
Semnificație
+=
v += 3
v = v + 3
-=
v -= 3
v = v - 3
*=
v *= 3
v = v * 3
/=
v /= 3
v = v / 3
%=
v %= 3
v = v % 3
//=
v //= 3
v = v // 3
**=
v **= 3
v = v ** 3
2.3. Erori frecvente
Nu avem pretenţia să epuizăm şirul erorilor posibile întrucât fantezia
noastră când greşim este fără limită. Vom încerca totuşi să prezentăm cele
mai frecvente erori care apar.
1. Uităm să punem semnul înmulţirii!
Avem de calculat 1+ab (a şi b sunt variabile întregi sau reale). Am folosit
intenţionat notaţia cu care suntem obişnuiţi de la matematică. Unii vor
scrie 1+ab în loc de 1+a*b. În cazul în care facem această greşeală, ne va
apărea un mesaj de eroare. Acesta se va referi la faptul că ab este un
simbol nedefinit (se presupune că ab este o variabilă sau o funcţie care nu
a fost definită corespunzător).
60
2. Nu scriem corect numitorul!
De exemplu, se cere să se evalueze expresia:
E
1
xy
(x, y conțin valori reale, diferite de 0). Dacă scriem 1/x*y se va evalua
expresia
1
y y.
x
x
Corect este 1/(x*y). În acest fel, se calculează la început produsul dintre x şi
y, apoi se împarte 1 la acest produs.
3. În cazul expresiilor care conţin o sumă (diferenţă) atât la numărător,
cât şi la numitor, nu se scrie numărătorul (numitorul între paranteze).
Exemplu: Să se evalueze expresia
E
a b
cd
(a, b c, d variabile reale şi c+d0). Unii vor scrie a+b/c+d, alţii a+b/(c+d).
Corect este (a+b)/(c+d).
Exerciţiu: ce expresii se evaluează în formele evidenţiate ca eronate?
4. Atenție la împărțirea la zero!
Dacă expresia de la numitor are vreodată valoarea zero, veți avea eroare
de la interpretor, similară cu cea de mai jos:
61
2.4. Câteva funcții utile (built-in)
Considerăm funcțiile1 precum niște subprograme care au un rol bine
definit și ne ajută să efectuăm anumite operații complexe, iar pe unele
le-am folosit deja în Python: (input, print, int, float, ...).
2.4.1. Funcția abs()
Funcția abs(număr) primește ca argument un număr și oferă ca rezultat
valoarea sa absolută, adică modulul.
Exemple.
* Dacă argumentul este un număr complex, de forma z = a + bj, atunci
rezultatul este magnitudinea:
Așadar:
1
Lista completă a funcțiilor built-in o găsiți la adresa
https://docs.python.org/3/library/functions.html
62
2.4.2. Funcția eval()
Funcția eval() primește ca argument o expresie sub forma unui șir de
caractere și oferă ca rezultat evaluarea acesteia:
Analizați si programul următor, care citește de la tastatură o expresie,
iar programul afișează rezultatul și tipul de date obținut:
exp = eval(input())
print(exp)
print(type(exp))
În acest caz, funcția input primește textul introdus de la tastatură și îl oferă
apoi ca rezultat - mai sus am executat programul de două ori.
Atenție, dacă introducem explicit expresia fără a folosi apostrofuri ori
ghilimele, vom avea eroare de sintaxă (tipul de date acceptat este str):
63
2.4.3. Funcția id()
Am prezentat noțiunea de variabilă și faptul că valoarea reținută este
regăsită în memoria internă a calculatorului.
Lucrurile devin interesante deoarece, în fapt, valoarea reținută de o
variabilă la atribuire este un obiect cu o identitate unică:
Așadar, numărul întreg 19 are identificatorul unic 1355204816, precum și
variabilele a și b (indică aceeași valoare întreagă). Similar, este la fel pentru
orice altă variabilă ori valoare numerică, ca 19.0, de tip float, care are
identificatorul unic 42368432.
Trebuie să înțelegeți că în Python totul este un obiect, chiar și numerele.
2.4.4. Funcția len()
Această funcție primește ca parametru un obiect, precum un șir de
caractere și oferă ca rezultat lungimea acestuia (numărul de elemente).
Exemplu. Un șir de caractere este format din niciunul, unul sau mai multe
caractere:
64
2.4.5. Funcția round()
Funcția round() are rolul de a rotunji o valoare numerică primită ca
argument cu o anumită precizie (număr de zecimale).
Forma sa generală este:
round(numar[,zecimale])
Al doilea parametru este opțional. Dacă nu este impus, rotunjirea se va
face spre cel mai apropiat număr întreg.
Exemple. Am rulat aceste comenzi în consolă:
Atenție însă, există situații în care rotunjirea nu poate fi efectuată totuși
cum ne-am aștepta deoarece fracțiile zecimale nu pot fi reprezentate
perfect ca un număr de tip float.
În mod normal, valoarea rezultată ar fi trebuit să fie 2.68.
Nu este o eroare, ci doar o limitare a mediului2 de programare Python.
2
Vezi discuția oficială aici:
https://docs.python.org/3/tutorial/floatingpoint.html#tut-fp-issues
65
2.5. Mai mult despre print()
Până acum am folosit funcția print() pentru a afișa anumite date singulare
ori mai multe, despărțite prin operatorul virgulă, ca mai jos:
Observăm că implicit datele (obiectele) primite ca argument sunt afișate pe
o singură linie, despărțite fiind de câte un spațiu între ele, în cazul în care
sunt mai multe enumerate.
Forma generală simplificată a instrucțiunii este:
print(obiecte[, sep=' ', end='\n'])
Obiectele vor fi tipărite în consolă, separate printr-un spațiu și terminate
prin trecerea pe rândul următor (valori implicite și opționale pentru
argumentele sep și end, care trebuie să fie de tip str, după cum se vede).
Exemple. Mai jos am tipărit prima oară două obiecte, un șir de caractere și
un număr, apoi cinci numere separate prin caracterul "_":
sau cu "." ca separator și semnul exclamării la final:
66
Probleme rezolvate
1. Se citește de la tastatură un număr format din 3 cifre. Să se afișeze
numărul obținut prin citirea cifrelor de la dreapta la stânga.
Exemplu. Pentru n = 123, se va afișa 321.
Vom folosi operatorii // și %, pentru câtul și restul împărțirii:
2. Fizică. Fiind citite de la tastatură timpul și viteza, afișați distanța parcursă
de un corp (toate măsurile sunt exprimate în S.I.).
Știm că formula de calcul este d = v*t. Așadar
67
3. Se citește de la tastatură o lungime exprimată în milimetri. Să se afișeze
valoarea în sistem internațional [S.I.].
1m = 100cm = 1000mm
deci...
4. Se citește un număr natural n. Să se afișeze valoarea sumei 1+2+3+...+n.
Simplu. Știm că formula de calcul este
S
n (n 1)
2
deci programul va fi
Atenție la paranteze. Apoi, dacă dorim să afișăm valoarea întreagă, putem
folosi int(n*(n+1)/2) sau round(n*(n+1)/2) – expresia este convertită
implicit spre tipul float datorită operatorului "/".
68
Probleme propuse / exerciții
1. Cum scriem în Python expresiile de mai jos?
a)
E
1
2
1
3
1
;
Observaţie. Expresiile vor fi transpuse
identic, fără simplificare. Acesta este
numai un exerciţiu de transcriere.
4
b)
E
1
1
1
;
23 3 4 45
c)
E
1 2 5 6 9 10
;
3 4 7 8 11 12
Atunci când veţi scrie programe, este
bine să simplificaţi voi expresiile. În acest
fel, calculatorul nu va efectua la fiecare
executare a programului calcule inutile.
2. Evaluaţi expresiile de mai jos precizând rezultatul şi tipul expresiilor:
a) x+1.5, unde x este o variabilă întreagă ce conţine numărul 7
b) x<=4, unde x este o variabilă întreagă ce conţine numărul 4
c) a+1>3, unde a este o variabilă reală care conţine numărul 3
d) 1/4
e) 6//2
f) x/y+y/x unde x şi y sunt variabile întregi şi conţin, respectiv, 1 şi 6
g) x<3 or x>6 (unde x este o variabilă reală)
h) x<3 and x>6 (la fel ca mai sus)
3. Fie x o variabilă de tip int. Pentru ce valori ale lui x expresia: x+7==8*x ia
valoarea True? Dar pentru expresia: 2*x+3==6?
4. Ce erori de sintaxă conţin expresiile de mai sus?
a) (x+3, unde x este o variabilă întreagă
b) x+1, unde x este o variabilă de tip str (șir de caractere)
c) (x+1/((x+2)-1 (x este variabilă întreagă)
d) y=5x (x,y sunt variabile reale)
69
5. Considerăm
a = 2
b = 5
Care este valoarea rezultată în urma evaluării expresiei de mai jos?
True == a < b
Dar True == (a < b) ?
Dar not a + b ?
Dar a += b+1 ?
Explicați rezultatele.
6. Se citește de la tastatură un volum exprimat în litri. Să se afișeze
valoarea în decilitri, centilitri și mililitri.
7. Se citește de la tastatură un număr format din 4 cifre. Să se afișeze
numărul obținut prin citirea cifrelor de la dreapta la stânga.
Exemplu. Pentru n = 1234, se va afișa 4321.
8. Se citește un număr format din exact 3 cifre. Modificați valoarea
numărului a.î. cifra zecilor și cea a sutelor să fie interschimbate.
Exemplu. Pentru n = 741, se va afișa 471.
9. Se citește un număr format din exact 2 cifre. Afișați suma pătratelor
cifrelor sale.
Exemplu. Pentru n = 25, se va afișa 29, adică 22+52.
10. Se citește un număr natural format din 5 cifre. Afișați suma cifrelor sale.
Exemplu. Pentru n = 12134, se va afișa 11.
11. Se citește un număr natural format din 3 cifre. Afișați produsul cifrelor
sale. Exemplu. Pentru n = 12134, se va afișa 24, adică 1*2*1*3*4.
12. Se citesc de la tastatură mediile generale ale celor mai buni 5 elevi.
Afișați media acestora.
13. Să se afișeze 2n+m, unde n și m sunt două numere naturale citite.
70
Fără OOP nu putem continua...
Avem nevoie doar de 3 pagini.
Ne-am oprit puțin din studiu deoarece în Python aproape orice este
reprezentat ca un obiect, iar noțiunea este esențială.
Am folosit pe alocuri termenii de obiect sau constructor. Înainte de
a prezenta instrucțiunile limbajului Python, anumite colecții de date sau
șirurile de caractere, trebuie să înțelegeți un principiu esențial în ziua
de astăzi – programarea orientată pe obiecte.
Conceptul poate fi întâlnit sub diverse denumiri, cum ar fi: programare
orientată pe obiecte, programare obiectuală, programare orientată spre
obiect ori OOP – Object Oriented Programming.
Suntem înconjurați de obiecte în jurul nostru care au anumite proprietăți
ori caracteristici de bază și funcții care ne fac viața mai ușoară.
Să considerăm de exemplu mașina de spălat rufe pe care o avem în casă:
Producător: X
Model: XYZ
Înălțime: 1.2m
Lățime: 0.5m
Adâncime: 0.4m
Capacitate de spălare: 8kg
Număr de programe: – 15
Buton de: Pornire/Oprire/Pauză
Bineînțeles că fiecare produs are mult mai multe caracteristici ori funcții
diferite sau nu, însă orice mașină de spălat le deține și pe acestea.
Deci, putem defini o clasă de obiecte numită mașină_de_spălat.
Am căutat pe Internet... Bosch WAN28108GB, Indesit IWC8125, Beko
WTG841 sunt mașini de spălat rufe cu anumite caracteristici. Toate însă fac
parte din aceeași clasă numită de noi ca exemplu - mașină_de_spălat.
71
Așa și în cazul programării orientată pe obiecte putem defini conceptele de
clasă și obiect.
Prin încapsulare înțelegem mecanismul prin care datele (variabilele)
și funcțiile (numite în acest caz și metode) sunt plasate împreună, într-o
unică structură, numită clasă.
Exemplu. Definim clasa
mașină_de_spălat
Proprietăți (numite date membre)
producător
înălțime
adâncime
număr_de_programe
model
lățime
capacitate_de_spălare
serie
Funcții oferite (metode)
on() / off() / pause()
alege_programul(n)
Atunci când un constructor creează o nouă mașină de spălat, este realizat
un nou obiect al clasei mașină_de_spălat, care este o instanțiere a
acesteia. Clasa este doar o structură abstractă, precum vedeți!
Definiți și voi clase de obiecte, cum ar fi autoturism, televizor ori telefon.
Rețineți termenii de încapsulare, clasă, obiect, constructor și instanțiere!
Nu va fi prezentată teoria OOP acum, însă avem nevoie de aceste noțiuni
pentru a înțelege cele ce urmează.
Revenim la Python 3. Tipurile de date prezentate până acum, int, float,
complex, bool și str, sunt clase de obiecte. Scriem în consolă
Ce se întâmplă? Se creează un nou obiect reținut de variabila n, prin
constructorul (funcția) int() care instanțiază clasa numerelor întregi cu
semn, adică int, cu valoarea datei membru fiind 7. După cum vedeți,
numele constructorului este același cu cel al clasei respective.
72
Alt exemplu. Definim variabile ce rețin obiecte de tip float:
Observăm constructorul float() de fiecare dată.
Apoi, am folosit metoda is_integer() care testează dacă valoarea (data
membru) reținută este sau nu un număr întreg cu semn. Accesul la
metodele unei clase se realizează utilizând operatorul punct ".":
obiect.metoda(argumente)
O metodă a clasei respective poate sau nu să întoarcă un rezultat. Mai sus
ne specifică o valoare de adevăr, însă altele pot avea rolul doar de a
prelucra informația. De asemenea, argumentele pot lipsi, depinde doar de
definiția metodei.
Atenție. Metoda is_integer() aparține clasei float. Dacă încercați să o
apelați pentru un obiect de tip int, veți obține eroare:
Metoda nu a fost definită pentru clasa int deoarece nu are rost... știm că
obiectul conține deja un întreg!
REȚINEȚI!
Un obiect este instanțierea unei clase efectuată de un constructor.
Clasa are încapsulate date și metode proprii care sunt structurate abstract.
Vom folosi metodele claselor din plin în cele ce urmează. Putem continua!
73
Șiruri de caractere
4.1. Introducere
Am mai folosit șirurile de caractere până acum. Se atribuie valorile simplu,
scriind textul între apostrofuri, ghilimele sau combinație de trei cu trei,
pentru a scrie un text pe mai multe rânduri. Exemplificăm din nou:
Mai știm că tipul de date, adică clasa obiectelor create, este str, ce are ca și
constructor funcția str():
iar dacă scriem s2 = str(), vom avea în variabila s2 un obiect ce conține un
șir de caractere gol ('').
74
De asemenea, Python are capacitatea să se adapteze, deci o atribuire ca
cea de mai jos, fără a impune explicit tipul / clasa
sir1 = 'Salut!'
conduce automat la crearea unui obiect de tip str reținut de sir1.
Mai știm că funcția input() citește de la tastatură un șir de caractere
introdus de utilizator pe care îl returnează ca tip str. Datele citite trebuie
eventual convertite explicit spre un tip de date pentru prelucrare, altfel
putem avea erori la interpretare:
Bun. Să vedem ce putem face mai mult!
Notă. În alte limbaje de programare există tipul char, care reține un singur
caracter - Python nu oferă această posibilitate deoarece se consideră
că putem defini un șir de caractere cu lungimea 1 – simplu.
4.2. Operatorii + și *
4.2.1. Operatorul + (concatenarea)
În cazul șirurilor de caractere, operatorul de adunare "+" are rolul de a
alătura două șiruri, precum mai jos, deja prezentat în Capitolul 1:
blank, spațiu liber
Nu o să insistăm mult pe acest aspect. Pur și simplu operatorul alătură
două șiruri de caractere în urma efectuării operației.
Ne putem juca cu spațiile (caracterul blank), cu mai multe șiruri, testați!
75
Atenție la tipul de date:
ambele trebuie să fie de tip str, altfel obțineți eroare. Variabila n reține un
obiect de tip int, iar m, unul de tip str. Folosiți conversia str(n)+m!
4.2.2. Operatorul * (repetiția)
Pentru două valori numerice, operatorul "*" reprezintă înmulțirea. În cazul
unor operanzi de tip str, acesta are rolul de a multiplica valoarea:
4.3. Accesul la caracterele șirului
Bineînțeles că este important să putem accesa unul sau mai multe
caractere citite ori reținute de o variabilă de tip str, iar limbajul Python ne
oferă un mecanism ușor de folosit.
Priviți exemplul de mai jos:
s1
c
a
r
a
c
t
e
r
0
1
2
3
4
5
6
7
Considerăm o variabilă s1 care reține șirul "caracter".
76
Indicele primului caracter este 0, iar ultimul 7, adică 8-1, unde 8 este
numărul de caractere conținute de obiect. Folosind un anumit indice și
operatorii "[" și "]" împreună, avem acces la caractere:
Nu putem actualiza o anumită valoare pentru un caracter, deoarece vom
obține eroare de la interpretor:
însă putem actualiza valoarea reținută de variabila s1:
Indexul negativ. Știind lungimea șirului de caractere, putem accesa
caracterele acestuia de la dreapta la stânga folosind index-urile negative.
Astfel, ultimul caracter are indexul -1, penultimul, -2, ș.a.m.d.
Evident, obținem eroare dacă depășim în acest caz -8, -9 nu există!
77
4.4. Lungimea unui șir de caractere
Am mai folosit funcția implicită (built-in) numită len(), iar aceasta ne
permite să obținem în acest caz lungimea unui șir de caractere:
deoarece
I
m
i
0
1
2
3
p
l
a
c
e
4
5
6
7
8
9
S
t
a
r
10
11
12
13
14
W
a
r
s
!
15
16
17
18
19
Precizăm din nou că indicii pornesc de la 0 și se opresc la len()-1.
4.5. Subșiruri (feliere, din engleză - slicing)
De multe ori avem nevoie doar de o anumită porțiune din șirul reținut de o
variabilă de tip str, iar Python ne vine în ajutor! Similar accesului la un
singur caracter din șir, folosind indicii și operatorul două puncte ":", putem
obține ușor un subșir:
sir_de_caractere[index_inceput : index_final[ : pas]]
De exemplu, considerăm varabila s care conține șirul:
Atenție! Ultimul caracter precizat prin index nu este reținut!
Am afișat caracterele de la indicii 3 până la 8, apoi de la 15 până la 20
(scriem ultimul indice dorit, +1).
Ne putem juca apoi:
78
Variabila s1 reține șirul de caractere "Sinaia", apoi șirul s2 reține primele
trei caractere, adică "Sin", pe care le afișăm împreună cu restul conținutului funcției print() care are ca separator spațiul implicit.
Rețineți faptul că nu puteți modifica ori șterge o parte dintr-un șir de
caractere, acesta este nemodificabil (în engleză, immutable). Puteți totuși
șterge definitiv obiectul prin folosirea cuvântului cheie del:
Aplicație. Fiind citit un șir de caractere, afișați inversul său (de la dreapta
la stânga). Dacă alegem pasul -1 și lăsăm fără conținut celelalte atribute
H
a
i
0
1
2
3
l
a
4
5
6
m
u
n
t
e
!
7
8
9
10
11
12
obținem șirul citit invers, de la dreapta la stânga:
sau putem scrie și așa
s[len(s)-1::-1]
Notă. În acest caz, nu putem scrie indexul final deoarece ar fi -1 (ultimul
caracter, "H", are indexul 0) ... iar -1 conduce iar la dreapta șirului.
79
4.6. Apartenența – in și not in
Putem verifica dacă un caracter ori un subșir este prezent într-un șir de
caractere. Analizați operatorul in și grupul not in în exemplul de mai jos:
Șirul "Star" se găsește în a, însă "StarWars" nu, atenție la lipsa spațiului
între cele două cuvinte. Apoi, nu este adevărat că "Wars" nu este subșir al
conținutului obiectului a de tip str.
După cum observați, rezultatul expresiilor este de tip bool, adică o valoare
True sau False.
4.7. Funcțiile built-in min() și max()
min() și max() – întorc în acest caz minimul și, respectiv, maximul alfabetic
din cadrul șirului pe care îl primesc ca argument:
În Capitolul 3 a fost prezentată noțiunea de metodă (o funcție adică) ce
aparține unei clase de obiecte.
Clasa str conține un set puternic de metode pe care le putem folosi la
prelucrarea șirurilor de caractere.
Să le vedem în continuare...
80
4.8. O parte dintre metodele clasei str
Numărul metodelor pe moment este mare1 și le vom prezenta doar pe
unele care au o importanță deosebită în prelucrarea șirurilor de caractere
pentru voi, la început de drum.
isdecimal() întoarce True dacă toate caracterele sunt numere
zecimale, adică de la 0 la 9; altfel, întoarce False:
capitalize() întoarce un șir de caractere cu prima literă mare:
lower() întoarce un șir de caractere cu toate literele mici:
upper() întoarce un șir de caractere cu toate literele mari:
1
Lista completă o găsiți și aici:
https://docs.python.org/2.5/lib/string-methods.html
81
swapcase() întoarce un șir de caractere cu toate literele inversate din
mari și mici și viceversa:
startswith(prefix[, început, sfârșit]) întoarce True dacă șirul de
caractere începe cu șirul specificat prin prefix; altfel, întoarce False.
Argumentele început și sfârșit sunt opționale și specifică indexurile
între care să se efectueze căutarea:
endswith(sufix[, început, sfârșit]) întoarce True dacă șirul de
caractere se termină cu șirul specificat prin sufix; altfel, întoarce
False. Argumentele început și sfârșit sunt opționale și specifică
indexurile între care să se efectueze căutarea:
count(subșir[, început, sfârșit]) întoarce numărul de apariții a unui
subșir în șirul dat; dacă nu este găsit, se returnează valoarea 0:
82
find(subșir[, început, sfârșit]) întoarce cel mai mic index de la care se
găsește subșirul în șirul dat; dacă nu este găsit, se returnează
valoarea -1. Argumentele început și sfârșit sunt opționale și specifică
indexurile între care să se efectueze căutarea:
rfind(subșir[, început, sfârșit]) întoarce cel mai mare index de la care
se găsește subșirul în șirul dat; dacă nu este găsit, se returnează
valoarea -1:
replace(șir1,șir2,[max_ap]) întoarce un șir nou de caractere care are
toate aparițiile lui șir1 înlocuite cu șir2. Argumentul opțional max_ap
permite setarea unui număr maxim de înlocuiri; dacă nu este
specificat, se consideră toate:
strip([șir]) întoarce un șir nou de caractere care are eliminate spațiile
ori caracterele (opțional, din șir) de la început și sfârșit:
sau
83
Observați că acest cuvânt este un palindrom2, adică se citește la fel
de la stânga la dreapta precum și de la dreapta la stânga.
Metoda strip a citit și eliminat șirul " aer" și de la dreapta la stânga
citit la final ("rea ").
Priviți și exemplul de mai jos:
Atenție – sunt șterse toate combinațiile însă:
Subșirurile de la început și de la sfărșit au fost eliminate, precum și
litera w și spațiile: "www", "w", "org" (e inversul lui "gro"), ".".
Această metodă este fină, însă foarte puternică!
Există și metodele lstrip() și rstrip() care au un rol similar, însă elimină
caracterele doar de la început (l – left, stânga) ori, respectiv, sfârșitul
(r – right, dreapta) obiectului.
2
Citiți mai mult despre palindromuri aici:
http://www.jocuridecuvinte.ro/palindrom.htm
Alte exemple de cuvinte: cojoc, reper, rotitor, ori propoziții
ele fac cafele
ene purta patru pene
84
4.9. Compararea șirurilor
Oricât ar părea de curios, şirurile de caractere pot fi comparate.
Spre exemplu, două şiruri de caractere (notate cu a şi b), se pot găsi în una
dintre relaţiile:
a==b
a>b
a<b
cele două şiruri sunt egale
şirul a este mai mare decât şirul b
şirul a este mai mic decât şirul b
(mai exact, putem folosi toți operatorii: !=, ==, >=, >, <, <=)
Dar cum se pot compara două şiruri? Simplu – caracter cu caracter. Dacă
un caracter urmează altuia în lista Unicode, atunci el are drept cod un
număr mai mare decât al caracterului căruia îi urmează (deci în ordine
alfabetică). Exemplu:
Şirurile sunt succesiuni de caractere. Prin urmare, compararea se face pe
caractere. În continuare prezentăm algoritmul de comparare a două şiruri.
Fie două şiruri, notate cu a (conține m caractere) şi b (conține n caractere).
Se compară codurile primelor două caractere (aflate în stânga şirurilor,
de indice 0). Avem trei posibilităţi:
dacă codul primului caracter al şirului a este mai mare decât codul
primului caracter al şirului b, atunci a>b
dacă codul primului caracter al şirului b este mai mare decât codul
primului caracter al şirului a, atunci a<b (b>a)
în caz de egalitate se compară codurile caracterelor de indice 1.
...
85
Dacă m<n şi în urma comparării primelor m caractere a rezultat
egalitate, atunci a<b (b are mai multe caractere).
Dacă m>n şi în urma comparării primelor n caractere a rezultat
egalitate, atunci a>b (a are mai multe caractere).
Dacă m=n şi în urma comparării tuturor caracterelor a rezultat
egalitate, atunci cele două şiruri sunt egale (a=b).
Exemple:
a='abc'; b='bactr'. Atunci a<b, pentru că a[0] este "a" şi are codul mai
mic decât b[0] care este "b".
a='abc'; b='aba'. Atunci a>b, deoarece codul lui a[0] este egal cu codul
lui b[0], codul lui a[1] este egal cu codul lui b[1], iar codul lui a[2] este
mai mare decât codul lui b[2].
a='abc'; b='abca'. Aici m=3, n=4. Atunci a<b, codul lui a[0] este egal cu
codul lui b[0], codul lui a[1] este egal cu codul lui b[1], codul lui a[2]
este egal cu codul lui b[2] şi n>m (şirul b are mai multe caractere).
Compararea şirurilor de caractere este extrem de utilă în sortarea
alfabetică a cuvintelor (ca și în dicţionar). Ordinea astfel impusă se mai
numeşte şi ordine lexicografică.
4.10. Formatarea șirurilor
Să presupunem că avem numărul întreg 23 reținut de variabila n și un șir
de caractere "abc" reținut de variabila s. Bineînțeles că operatorul de
adunare / concatenare "+" va obține o eroare:
Câteodată avem nevoie de o astfel de operație. Ce putem face?
86
Păi, ne putem gândi să realizăm o conversie explicită asupra obiectului de
tip int spre str, ca mai jos:
Totuși, pentru un program complex, Python ne oferă un mecanism
elegant și ușor de a "formata" un anumit șir de caractere, folosind
metoda format().
Exemplu de referință. Priviți codul următor:
Acum, metoda format() primește ca argumente două date: un șir de
caractere și o valoare numerică. Observați că "Vlad" este introdus în locul
primelor acolade, iar numărul 38, în locul celui de-al doilea grup:
s = 'Salut, {}! Varsta ta este de {} ani!'
s.format('Vlad', 38)
Toate conversiile sunt create automat spre tipul de date str. Magie...
Putem scrie și ca mai jos, astfel încât să nu ne încurcăm prea tare le ordinea
introducerii argumentelor metodei:
s = 'Salut, {0}! Varsta ta este de {1} ani!'
s.format('Vlad', 38)
În acest caz, am scris indicii de la 0 la n-1 parametri în locația
corespunzătoare. Sau:
s = 'Ai {1}, draga {0}!'
s.format('Vlad', 38)
87
Și mai mult, putem folosi argumente de tip cuvinte cheie:
ori și cu ajutorul variabilelor:
sau citite de la tastatură:
Metoda format() poate primi oricâte date ca și argumente, precum
programul prezentat mai jos:
Metoda funcționează și cu argumente mixte:
88
Atenție. În cazul argumentelor mixte, cuvintele cheie se impun după cele
poziționale. Deci, mai întâi le scriem pe cele care au indici, apoi spre final
pe cele unde specificăm cuvinte cheie, ca "oras=". Mai jos avem eroare:
Rețineți termenii:
parametrii poziționali sunt specificați prin indici;
parametrii cuvinte cheie sunt specificați printr-un nume unic.
Bineînțeles că ar putea fi scrise zeci de pagini pentru a detalia fiecare
secțiune în parte, însă caracterul acestei cărți este unul introductiv și vă
încurajez să fiți autodidacți (vezi Bibiliografia).
Probleme rezolvate / propuse
1. Realizați un program care citește de la tastatură un șir de caractere și
afișează de câte ori apare litera "a" în text.
Exemplu. Pentru "Mihai este la mare." se va afișa 3.
Rezolvare. Simplu – folosind metoda count():
s = input()
print(s.count("a"))
Exercițiu propus. Realizați un program similar care afișează de câte ori
apare fiecare vocală din alfabetul englezesc în textul citit și apoi la final,
totalul aparițiilor lor. Atenție la detalii – mai jos e stilizat puțin rezultatul:
89
2. Realizați un program care citește de la tastatură un șir de caractere și
afișează următoarele informații:
a)
b)
c)
d)
lungimea șirului
dacă există vreo apariție a consoanei "x"
dacă șirul începe cu "a" sau "A"
daca șirul se termină cu "."
3. Verificați dacă un șir de caractere citit are sau nu lungimea mai mare
decât 20.
Exemplu. Pentru "Eric este un baiat istet in clasa a VII-a." se va afișa True.
4. Se citesc două cifre nenule sub formă de text, una după cealaltă. Afișați
numerele cu cifre distincte care se pot forma cu acestea.
Exemplu. Pentru "2" și "4", tipărim 24 și 42.
Rezolvare. Folosim operatorul "+", care concatenează șirurile:
Exercițiu propus. Realizați un program similar care citește 3 cifre...
5. Fiind citite un nume de oraș, o țară și o cifră, afișați un text la alegere.
Exemplu. Pentru "Paris", "Franta" și "7" am tipărit "Super! Si eu am vizitat
Franta, iar in Paris am petrecut minunat 7 zile".
6. Utilizatorii introduc de la tastatură datele personale, poate și din
greșeală, cu litere mici (spre exemplu, "matei" și "Ionescu"). Creați un
program ce le citește numele și prenumele, apoi le afișează în stil
academic, ca mai jos:
90
7. Fiind citite trei șiruri de caractere, afișați-le alăturate fără spații între ele.
Încercați și fără operatorul "+"... folosind doar funcția print().
8. Verificați, prin afișarea True sau False, dacă un șir citit de la tastatură
conține doar cifre de la 0 la 9.
Exemplu. Învățați să citiți și să afișați elegant datele folosind anumite
caractere ori texte sugestive, ca mai jos:
Mai sus, ca și în alte exemple, am delimitat datele de intrare de cele de
ieșire folosind print('------------'). Apoi am afișat un text care să
indice rostul răspunsului oferit automat de program. Încercați...
9. Se introduce un șir de caractere. Afișați-l cu majuscule, citit de la dreapta
la stânga.
10. Fiind citit un șir de caractere, afișați dacă primul caracter este identic
cu ultimul introdus (True/False).
Un mic proiect. "curriculum vitae". Realizați un program care citește de la
tastatură anumite date despre utilizator, cum ar fi: nume, prenume, anul,
luna și data nașterii, informații despre școală / educație, limbi străine
cunoscute, țări vizitate, pasiuni, diplome ori certificate obținute, ș.a.m.d.
Atenție la modul în care solicitați informațiile.
Atenție la modul în care prezentați informațiile prelucrate.
Aveți destule unelte necesare învățate până acum.
Fiți inventivi! Succes!
91
Colecții de date
Python oferă implicit patru tipuri de colecții de date: liste, tupluri, seturi și
dicționare, iar în acest capitol le vom studia amănunțit.
5.1. Liste
5.1.1. Ce este o listă?
Priviți lista de mai jos scrisă în consola interactivă:
Ce observăm? O listă conține mai multe date, în acest caz șiruri de
caractere, care sunt grupate și separate prin operatorul virgulă "," și este
definită direct între două paranteze pătrate.
Accesul la elementele listei se face similar șirurilor de caractere, folosind
indexarea de la 0 la len()-1, adică lungimea listei în acest caz, minus unu.
Putem folosi și constructorul clasei, adică funcția list():
În primul caz, doar am apelat constructorul fără argumente, iar variabila
lista1 conține o listă vidă. În cel de-al doilea, pentru lista2, am apelat
constructorul cu parametru – atenție la paranteze!
92
Listele sunt obiecte ce conțin date ordonate și au un număr finit de
elemente care pot fi apelate folosind indecși. De asemenea, listele pot fi
modificate după creare, veți vedea în cele ce urmează.
5.1.2. Accesul la elemente
Ca și în cazul șirurilor de caractere, priviți:
Am creat o listă numită lista1 și am afișat-o.
Am tipărit primele 3 elemente, adică lista1[0], lista1[1] și lista1[2].
Amintesc din nou că ultimul indice (3) nu se ia în considerare...
Apoi, am afișat și elementele de la indicele 3 spre dreapta, adică
lista1[3], lista1[4] și lista1[5] (nu am specificat indicele de sfârșit,
așadar au fost tipărite toate).
Index negativ. Ultimul element al listei are indexul -1, penultimul are
-2, ș.a.m.d.
Observați ceva interesant. Elementele unei liste nu trebuie să aibă
același tip. Primele trei sunt de tip str, iar ultimele trei de tip int.
Folosind felierea, putem citi lista de la dreapta la stânga:
93
5.1.3. Modificarea elementelor
Pentru a modifica valoarea unui element, îi atribuim un nou conținut:
5.1.4. Ștergerea elementelor
Pentru a șterge elemente din listă, avem mai multe opțiuni.
1. Metoda remove(valoare) șterge primul element din listă care
conține valoarea trecută ca argument:
Așadar, al doilea element ce conține numărul 2 a rămas în listă,
fiind șters doar primul găsit, pe poziția 1.
2. Metoda pop(indice_optional) șterge și întoarce ultimul element din
listă ca rezultat, ori pe cel trimis ca argument prin indice_optional:
Funcția este utilă atunci când înainte de ștergere dorim să extragem
și să prelucrăm valoarea respectivă.
94
3. Folosim cuvântul cheie del care are rolul să șteargă din memorie
complet un obiect ori un element al unei liste:
Așadar, a fost șters elementul cu indicele 2, adică valoarea 3.
Ștergerea completă a listei se efectuează pe cale de consecință:
5.1.5. Adăugarea elementelor noi
Avem la dispoziție două metode cu rol de a adăuga unei liste elemente noi,
iar acestea sunt:
1. Metoda append(obiect) adaugă un element nou la sfârșitul listei, cu
valoarea trimisă ca și argument (am scris obiect deoarece un
element al unei liste reține în esență unul de un anumit tip):
95
Fiecare element fiind în esență un obiect, putem introduce de
exemplu o nouă listă la final, ca mai jos:
Deci, avem trei obiecte: două numere întregi cu semn și o listă care
conține alte două elemente ca numere întregi cu semn (int):
Accesul la componentele cu indicele 2 este efectuat cu ajutorul unui
set suplimentar de paranteze pătrate, adică indicele din interiorul
listei care este obiect. După cum observați, simpla scriere lista[2]
afișează lista formată din obiectele 3 și 4.
Rețineți faptul că folosind această metodă se poate adăuga, pe
rând, un singur element / obiect nou la sfârșitul listei.
2. Metoda insert(index, obiect) este superioară celei anterioare
deoarece adaugă un nou element / obiect în poziția dorită a listei,
mutând spre dreapta cu o unitate toate elementele deja existente:
Am introdus un element nou, adică șirul "d" în poziția 1.
96
5.1.6. Extinderea unei liste
Folosind metoda extend([lista]) putem adăuga câte elemente dorim la
sfârșitul listei, spre deosebire de celelalte care puteau doar unul:
sau cu ajutorul unei variabile ce reține o altă listă:
Am extins astfel lista1 cu elementele din lista2.
5.1.7. Operatorii + și *, in și not in
Putem alătura liste ori multiplica una precum în cazul șirurilor de caractere,
folosind primii doi operatori. Priviți exemplul de mai jos:
Testați voi dacă șirul "a" se găsește în lista1, lista2 ori lista3 folosind
comenzi ca "a" in lista1 sau "a" not in lista3!
97
5.1.8. Alte metode și funcții built-in utile
Pornim de la trei liste ca exemplu:
lista1 = ['a', 'b', 'c']
lista2 = ['d', 'c', 'b']
lista3 = [1, 2, 3, 4, 5, 2, 3]
funcția sum(lista_numerica,initial) oferă ca rezultat suma valorilor
elementelor unei liste care conțin doar valori numerice; opțional,
dacă initial este precizat, suma se adaugă acestei valori:
funcțiile min() și max() întorc cea mai mică și, respectiv, cea mai mare
valoare reținută de elementele listei:
În acest caz, funcționează și cu șiruri de caractere, fiind comparate
codurile Unicode, element cu element, precum ați învățat deja:
funcția len() întoarce numărul de elemente a unei liste:
98
any() și all() întorc True dacă măcar un element este True sau,
respectiv, toate sunt True:
metoda clear() șterge toate elementele, golind lista. Spre deosebire
de cuvântul cheie del, metoda păstrează obiectul de tip list, vid:
metoda count(obiect) întoarce numărul de apariții ale obiectului
trimis ca parametru în cadrul listei:
Deci 2 apare de două ori în lista3.
metoda sort() ordonează crescător elementele unei liste:
Putem ordona o listă și descrescător apelând funcția ca mai jos:
99
metoda reverse() inversează elementele listei, fie că sunt sortate în
vreun fel sau nu:
5.1.9. Exerciții propuse
Fiind date listele
prenume = ['Mihai','George','Ana','Dan','Ion','Geta','Vio']
varsta = [14, 23, 15, 14, 12, 41, 39]
încercați să rezolvați cerințele următoare:
a) cosiderând că fiecare persoană are asociată vârsta pe același indice,
afișați precum mai jos:
Mihai are varsta de 14 ani.
George are varsta de 23 de ani.
...
b) Adăugați în liste la final, corespunzător, datele: Andreea, 34 și Ioan,
23. Tipăriți ambele liste apoi.
c) Ștergeți datele din ambele liste despre Ana (atenție la indici).
d) Ordonați crescător ambele liste și afișați-le!
e) Ștergeți definitiv lista varsta. Verificați cu print() apoi.
f) Afișați primele trei elemente din lista prenume.
g) Afișați ultimele elemente din lista prenume.
h) Afișați lista prenume de la dreapta la stânga.
i) Extindeți lista cu una la alegere care să conțină alte prenume și afișați
apoi noua listă formată.
j) Tipăriți elementele cu indicii 2 și 4, apoi de la 0 la 5.
100
5.2. Tupluri
5.2.1. Ce este un tuplu?
În cadrul ultimului exercițiu am avut practic o situație în care tipurile de
date învățate nu prea ne pot fi de folos real. Presupunem că dorim să
prelucrăm date referitoare la mai multe persoane și să spunem că pentru
fiecare cunoaștem numele, prenumele, vârsta, înălțimea, orașul și județul.
Putem crea 6 liste, una pentru fiecare informație, însă precum ați observat,
dacă alterăm (adică modificăm cumva) una dintre liste, indicii nu mai
corespund, iar pozițiile nu mai pot fi accesate corect. Folosim tupluri!
Un tuplu este tot un fel de listă care are însă elementele ordonate și
nemodificabile, iar acestea se definesc între paranteze rotunde:
Mai sus am definit două tupluri, în cazul nostru pentru Mihai și Dana, să
spunem. Fiecare element al tuplurilor reține o anumită informație pe
care am introdus-o corespunzător, astfel încât să obținem o structură de
date coerentă. Știm deci că tuplurile create rețin vârsta la indicele 2,
iar județul la 5, etc. Astfel, avem mecanismul format pentru oricare altă
persoană și vom crea un tuplu pentru fiecare.
Obs. Pentru cei ce au studiat C++, tuplurile sunt similare tipului struct.
Nu putem adăuga, șterge sau modifica elementele definite într-un tuplu!
Orice operație ne oferă o eroare la compilare:
Ce putem face însă?
101
5.2.2. Accesul la elemente
Ca și în cazul listelor, putem accesa elementele unui tuplu folosind indici și
parantezele pătrate, cum suntem obișnuiți:
Am folosit mai sus indicii direct ori am selectat doar o parte dintre ei,
indecșii negativi și inversarea listei.
5.2.3. Lungimea unui tuplu
Bineînteles, folosim iar funcția built-in len():
5.2.4. Operatorul in și grupul not in
Deja cunoscuți, aceștia testează dacă o valoare se regăsește sau nu în
colecția de date respectivă:
102
5.2.5. Constructorul clasei tuple
Un tuplu este evident un obiect, iar clasa acestuia are o funcție cu rol de
constructor – de instanțiere a ei. În acest caz, funcția se numește tuple():
sau cu elemente deja asociate (atenție la paranteze, ori obțineți eroare):
Putem crea un tuplu care conține un singur element:
În primele două cazuri, am folosit constructorul tuple(), care a creat
automat obiectul ce conține doar caracterul "1". Observați că la afișare
există o virgulă după element, ce indică acest fapt. Dacă folosiți doar
parantezele rotunde, interpretorul Python le va considera ca și operator
simplu și va crea doar un obiect de tip str:
Așadar, regulile de sintaxă sunt importante!
103
Pentru a crea tuplul fără funcția constructor și cu un singur element, scriem
ca mai jos:
Adăugăm astfel o virgulă, după primul și singurul element, care indică tipul
de date creat – tuple.
5.2.6. Ștergerea unui tuplu
Așa cum am precizat, ștergerea unui element / obiect din cadrul unui tuplu
este interzisă. Totuși, putem șterge complet tuplul prin folosirea cuvântului
cheie del. Testați! Exemplu: del tuplu3.
5.2.7. Operatorii + și *
Similar aplicării pentru liste, operatorul "+" alătură două sau mai multe
tupluri, iar operatorul "*" are rolul de multiplicare a elementelor:
Evident că multiplicarea trebuie făcută cu un număr natural, altfel vom
obține eroare de interpretare:
104
5.2.8. Metodele clasei tuple
Clasa conține doar două metode:
metoda count(obiect) întoarce numărul de apariții ale obiectului
trimis ca parametru în cadrul tuplului:
Deci numărul 2 apare de două ori în obiectul tuplu.
metoda index(obiect) întoarce prima poziție (indexul) a obiectului în
cadrul tuplului:
Atenție, dacă obiectul nu este găsit, funcția întoarce o eroare de
interpretare și nu o anumită valoare:
Așadar, atenție la crearea programelor deoarece se sistează
executarea acestora la apariția unei astfel de erori.
Puteți apela însă la o serie de alte funcții built-in pe care le-am mai
prezentat anterior, cum ar fi: any(), all(), min(), max(), len(), reversed(),
sum(), etc.
Mai mult, funcția sorted() întoarce o listă cu elementele unui tuplu în
ordine crescătoare sau descrescătoare.
Exemplu. sorted(tuplu) sau sorted(tuplu, reverse=True).
105
5.2.9. Modificarea unui tuplu – un truc interesant!
Să presupunem că am introdus greșit valorile elementelor unui tuplu ori,
în cadrul programului, pur și simplu avem nevoie de modificări. Obiectul
este implicit nemodificabil, așadar vom folosi un truc – conversia explicită.
Plecăm de la un exemplu:
Pasul 1. Listele sunt obiecte modificabile, deci creăm una care să conțină
toate elementele tuplului pers1:
Constructorul list() a preluat conținutul tuplului, primit ca parametru și a
creat o listă reținută de variabila temp.
Pasul 2. Listele sunt obiecte modificabile, deci rescriem elementul de pe
poziția a doua corespunzător:
Pasul 3. Acum că este totul corect și cum ne-am dorit, reținem în variabila
pers1 datele, convertind explicit lista temp spre tipul tuple cu ajutorul
constructorului său:
Gata!
106
5.3. Seturi
5.3.1. Ce este un set de date?
Putem privi seturile precum niște mulțimi de la matematică. Elementele
unui astfel de tip de date sunt neordonate (nu putem folosi indici), iar
fiecare dintre ele este unic (se regăsește o singură dată). Totuși, este
permis să adăugăm ori să ștergem elemente.
Pentru a crea un set de date, se folosesc acoladele:
Pentru a crea un set folosind constructorul clasei, apelăm funcția set(), care
primește ca parametri valorile similar tuplurilor (atenție iar la paranteze):
Funcția built-in len() precizează și în acest caz numărul de elemente ale
obiectului, iar pentru a șterge complet un set de date, folosim cuvântul
cheie del, precum suntem obișnuiți.
De asemenea, cu ajutorul operatorului in și a grupului not in putem verifica
dacă este sau nu existent un obiect printre elementele acestuia:
Un set poate conține obiecte de tipuri diferite, ca și în cazul altor colecții de
date. Analizați exemplul următor:
107
Variabila set2 reține două numere reale (float), un întreg (int) și un tuplu
(tuple) cu două elemente de tip str.
Observație importantă. După formarea unui set, Python nu respectă
ordinea introducerii elementelor, precum vedeți, sugerând astfel lipsa
indexurilor pentru acces.
5.3.2. Adăugarea de noi elemente
Pentru a adăuga noi elemente unui set, avem la dispoziție:
metoda add(obiect) adaugă un singur obiect în cadrul setului:
metoda update() adaugă mai multe obiecte setului, iar acestea se
trimit ca parametri:
Putem adăuga și elementele unei liste, precum mai jos:
Ce observăm? Au fost adăugate doar obiectele diferite de cele
existente; în acest caz, doar șirul "H" (elementele sunt unice în set).
108
5.3.3. Ștergerea elementelor
Prima variantă pentru a șterge un element este să folosim metoda
discard(), care primește ca parametru un obiect:
De notat este faptul că dacă elementul nu este găsit în setul respectiv,
metoda nu întoarce o eroare ce ne poate opri programul:
Mai există opțiunea de a folosi remove(), metodă care de această dată va
ridica o excepție dacă elementul nu este regăsit în set:
Am mai întâlnit metoda pop() în cazul listelor – aceasta șterge ultimul
element al setului. Atenție însă, ordinea este aleatorie, deci nu vom ști
niciodată care obiect va fi eliminat...
Pentru a goli un set, folosim metoda clear():
109
5.3.4. Operații cu mulțimi
Nu o să prezint teoria mulțimilor aici, ați învățat-o sper la matematică și
o consider, de altfel, fascinantă. Limbajul Python, prin seturile de date,
ne oferă acces facil la unele dintre operațiile uzuale cu mulțimi.
Considerăm ca exemplu două mulțimi:
A 1,2,3,4,5,6,7
B 5,6,7,8,9,10
Operațiile de reuniune, intersecție, diferență și diferență simetrică sunt
prezentate mai jos:
A B 1,2,3,4,5,6,7,8,9,10
A B 5,6,7
A \ B 1,2,3,4
B \ A 8,9,10
AB ( A \ B) (B \ A) 1,2,3,4,8,9,10
Priviți în Python cât de ușor le putem implementa:
Operatorii folosiți au fost: "|" (reuniunea), "&" (intersecția), "-" (diferența)
și "^" (diferența simetrică).
110
Putem folosi și metodele clasei set, precum union(), intersection()
și difference():
Toate cele trei metode întorc un nou set care conține rezultatul.
Pentru a actualiza un set în urma efectuării operației, există metodele
update(), intersection_update() sau difference_update():
5.3.5. Clasa frozenset
În limbajul Python există și clasa frozenset, care permite crearea unui set
nemodificabil. Funcția constructor primește ca argument o colecție de date
pe care o transformă spre un set "înghețat", deci cu elemente unice,
nemodificabile și neordonate:
Puteți considera valorile conținute ca niște date constante ori cuvinte
cheie, care uneori sunt utile în cadrul programelor (vom reveni asupra lor
un pic mai târziu).
111
5.4. Dicționare
5.4.1. Ce este un dicționar?
În Python un dicționar este o colecție de date neordonată, indexată și
modificabilă, care conține oricâte perechi de valori asociate cheie-valoare
(evident, cheia este unică). Mai jos avem un prim exemplu de dicționar:
Pentru fiecare cuvânt cheie din stânga am asociat o valoare (un antonim) în
dreapta. Folosim caracterul două puncte ":" pentru a efectua asocierea,
iar pentru a delimita perechile, caracterul virgulă ",". Toate sunt scrise
în interiorul a două acolade, similar unui set de date.
Lungimea unui dicționar nu este 10, ci bineînțeles 5, adică numărul de
cuvinte cheie (perechi) pe care le-am introdus:
Așadar, fiecare pereche din dicționar este un element al acestuia.
Un dicționar nu este ordonat cu indecși propriu-ziși, ci accesul se face cu
ajutorul cuvintelor cheie din perechi. Dacă vrem să știm antonimul
cuvântului "rapid", scriem:
112
Va apărea o eroare dacă scriem:
deoarece tipul de date nu este ordonat.
Mai mult, dacă un cuvânt cheie nu este regăsit în structura de date, va fi
afișată o excepție / eroare:
Deci, indexul (cheia) nu a fost găsit(ă).
5.4.2. Clasa dict
Un dicționar este și el un obiect, adică instanțierea unei clase numită dict,
care are constructorul dict(). Așadar, pentru a crea un dicționar gol, fără
elemente componente, scriem:
sau cu perechi, ca mai jos:
Putem folosi și o listă de tupluri, ca în exemplul următor:
113
În acest caz, fiecare obiect al listei trimisă ca parametru conține un tuplu cu
două elemente – cheia și valoarea asociată.
Pentru a șterge un dicționar, folosim cuvântul cheie del, așa cum suntem
obișnuiți. Dacă dorim să îl golim, apelăm iar la metoda clear():
5.4.3. Metoda get()
Am precizat anterior faptul că putem accesa un element cu ajutorul unui
cuvânt cheie folosind parantezele pătrate, însă dacă nu este găsit în
dicționar, obținem o eroare ce ne blochează programul. Folosim elegant
metoda prezentată mai jos:
Metoda get() primește ca parametru un cuvânt cheie. Dacă există în
dicționar este afișată valoarea asociată, iar dacă nu, cuvântul cheie None.
Să vedem în continuare cum putem modifica ori adăuga elemente...
114
5.4.4. Modificarea și adăugarea perechilor de date
Pentru a modifica ori adăuga un o pereche de date în dicționar, folosim
atribuirea directă – structura este modificabilă:
Am creat un dicționar care conține două perechi de date. Apoi, am adăugat
una nouă formată din cuvântul cheie "mare" și valoarea asociată, "mic".
La final am modificat valoarea cheii respective cu una nouă, ca un update,
de dragul exemplului - "micut".
5.4.5. Din nou, operatorii in și not in
Pentru a testa dacă este sau nu o cheie în dicționar, putem folosi așa cum
suntem deja obișnuiți acești operatori:
Atenție, căutăm informația după cuvintele cheie (acestea sunt indexate) și
nu după valorile asociate! Dacă scriem:
"micut" nu este găsit în dicționar, deoarece există doar ca valoare asociată
cheii "mare".
115
5.4.6. Revenim la frozenset...
În paragraful 5.3.5. am prezentat clasa frozenset, care ne permite să
înghețăm un set cu valori unice. Cuvintele cheie dintr-un dicționar pot fi
reținute de un frozenset.
Exemplu. Presupunem că avem dicționarul de mai jos:
Acesta conține 5 cuvinte cheie, cu care vom forma un frozenset reținut de
variabila chei_antonime, prin apelul funcției constructor, care primește ca
parametru dicționarul (conversie explicită):
Observați că setul înghețat conține doar cheile, nu și valorile asociate.
116
Instrucțiunile limbajului Python
6.1. Instrucțiunea condițională If
6.1.1. Forma if .. else
Calculatorul poate fi programat să ia decizii, dar numai cum îl învăţăm noi!
Ce înţelegem prin decizie? Care este mecanismul prin care o maşină poate
lua decizii? Acesta este subiectul tratat în această secţiune.
Deciziile în programe se pot lua cu ajutorul instrucţiunii if. Forma generală
a instrucţiunii if este următoarea:
if expresie_logică:
instrucțiuni_1
else:
instrucțiuni_2
opțional, blocul else poate și lipsi
Modul de executare este următorul:
True
expresie_logică
instrucțiuni_1
False
instrucțiuni_2
Pasul 1. Se evaluează expresie_logică.
Pasul 2. Dacă expresia logică are valoarea True, atunci se execută setul de
instrucțiuni instrucțiuni_1. Altfel, dacă valoarea este False, se execută
setul instrucțiuni_2.
Observație. Vom folosi operatorii relaționali și cei logici pentru a forma
expresii de test pentru if.
117
Exemplul 6.1. Se citesc de la tastatură două numere întregi cu semn
diferite. Să se afișeze care este mai mare dintre ele.
După citirea celor două numere (n şi m), se execută instrucţiunea if.
În primul rând, se evaluează expresia logică. În exemplul nostru ea este
n>m. În cazul în care numărul reţinut de variabila n este mai mare decât cel
reţinut de variabila m, expresia logică ia valoarea True şi se tipăreşte n este
mai mare ca m. Contrar, expresia logică ia valoarea False şi se tipăreşte m
este mai mare ca n. Întrucât după if nu mai urmează nici o instrucţiune,
executarea programului se termină.
De exemplu, dacă variabila n reţine 3 şi variabila m reţine 4, se va tipări:
Exemplul 6.2. Se citește de la tastatură un număr real. Să se afișeze doar
dacă este mai mare ca zero.
Simplu... În acest caz nu avem nevoie de clauza else, deci scriem:
n = float(input('n = '))
if n>0:
print(n)
Dacă numărul real reținut de variabila n este mai mare ca zero, expresia
n>0 va fi True, iar instrucțiunea print(n) executată. Dacă nu, se trece mai
departe, adică în acest caz programul se încheie.
118
6.1.2. Forma if .. elif .. else
Exemplul 6.3. Citim de la tastatură două numere întregi cu semn (reținute
de n și m) și vrem să vedem care este mai mare dintre ele. În această
situație, ele pot fi și egale, deci sunt trei cazuri: n>m, n=m, n<m.
Putem folosi structura
if expresie_logică:
instrucțiuni_1
elif alta_expresie_logică:
instrucțiuni_2
else:
instrucțiuni_3
Pasul 1. Se evaluează expresie_logică.
Pasul 2. Dacă expresia logică are valoarea True, atunci se execută setul de
instrucțiuni instrucțiuni_1. Altfel, dacă valoarea este False, se testează
condiția din blocul elif. Dacă altă_expresie_logică este adevărată,
atunci se execută instrucțiuni_2, altfel instrucțiuni_3.
Revenim la exemplu și scriem programul:
Mai jos sunt prezentate rezultatele în urma executării programului de trei
ori, cu diferite date de intrare:
119
6.1.3. Instrucțiunea compusă - indentarea!
Am văzut faptul că în urma evaluării expresiei logice, fie într-un caz, fie în
altul, am executat o singură instrucţiune. Ce ne facem dacă într-unul (sau
în celelalte cazuri) trebuie executate mai multe instrucţiuni?
Pentru aceasta ne este de mare folos instrucţiunea compusă. Pentru cei ce
au lucrat în Pascal ori C/C++, aceasta era delimitată de begin și end,
respectiv de acolade. În Python totul e mai simplu, folosim indentarea!
Ce observăm? Atunci când am folosit instrucțiunea if, după ce am
scris caracterul două puncte obligatoriu și apăsam tasta Enter pentru
a introduce instrucțiunea asociată cazului, linia nouă era indentată fix
cu 4 caractere:
4 caractere
cea ce indică automat faptul că în interiorul lui if putem scrie un bloc
format din mai multe instrucțiuni, ... nu doar una.
Atenție!
Indentarea este obligatorie pentru instrucțiunile compuse, altfel vom
obține eroare la interpretare. La începutul cărții am precizat faptul că
limbajul Python pune accent pe forma lizibilă a redactării codului,
iar această regulă este esențială.
Exemplul 6.4. Să se scrie un program care citeşte un număr natural
(comanda). Dacă acesta este 0 se vor citi două numere întregi a şi b şi se va
tipări suma lor; contrar se vor citi două numere reale x şi y şi se va tipări
produsul lor.
În ambele cazuri trebuie executate bineînțeles mai multe instrucţiuni,
indentate corespunzător. Astfel, am folosit instrucţiunea compusă (şi
pentru un caz şi pentru altul):
120
instrucțiune compusă din 3 instrucțiuni,
indentate fiecare cu 4 caractere
altă instrucțiune compusă din 3 instrucțiuni,
indentate fiecare iar cu 4 caractere
Am executat mai jos programul de două ori:
Observații. În Python puteți folosi tasta Tab pentru indentare!
O singură instrucțiune care nu este indentată corect conduce la eroare:
121
6.1.4. Probleme rezolvate
Problema 1. Se citeşte o valoare întreagă. În cazul în care aceasta este pară
(se împarte exact la 2) se va tipări mesajul "am citit un număr par". Altfel,
programul nu va oferi nicun mesaj.
Rezolvare. Folosim forma simplificată a instrucțiunii if, iar la condiție
operatorul modulo (%):
Problema 2. Se citesc 4 valori reale a, b, c, d. Să se evalueze expresia:
a b, c d 0
E a b, c d 0
a b
cd 0
Exemplu numeric: fie a=1, b=2, c=3, d=4.
Avem c+d=7>0, rezultă că se va tipări a+b=1+2=3.0.
122
Problema 3. Se citește un număr întreg x. Să se calculeze expresia:
x 1, x 0
E
x 1, x 0
Rezolvare. Să analizăm programul de mai jos:
O eroare des întâlnită este cea a instrucţiunii scrise de două ori. Despre ce
este vorba? Din neatenţie, o anumită instrucţiune este prezentă în ambele
instrucţiuni compuse. Corect, ea trebuie pusă după if. Nu ar fi fost mai bine
să procedăm ca în programul următor?
Dacă procedăm ca în primul caz putem afirma că am scris un program lipsit
de eleganţă (în rest, ... este corect).
Problema 4. Scrieţi un program care verifică dacă un coleg / utilizator ştie
tabla înmulţirii. Elevul este întrebat cât fac 78, iar după răspunsul acestuia
calculatorul va răspunde printr-un mesaj corespunzător.
Rezolvare. Răspunsul elevului este memorat şi comparat cu răspunsul
corect (56). În caz de egalitate se tipăreşte mesajul "Corect!", altfel se
tipăreşte mesajul "Incorect, mai invata...":
123
Problema 5. Se citeşte x, un număr real. Să se evalueze expresia:
x,
x 0;
2 x,
0 x 10;
f
3 x, 10 x 100;
4 x, x 100.
Exemplu numeric: dacă x=15, el este mai mare decât 10 şi mai mic decât
100, deci f=315=45.0.
Rezolvare. Atenţie la modul în care au fost puse condiţiile. De exemplu,
dacă x nu este mai mic decât 0, înseamnă că este mai mare sau egal ca 0
(nu trebuie să testăm aceasta), iar dacă este mai mic decât 10 se calculează
2*x, altfel ştim că este mai mare decât 10, etc.
Ce observăm? Putem folosi mai multe clauze elif! Acesta este un mod
fantastic de a lucra în Python deoarece evităm câteodată să folosim
instrucțiunile if imbricate (adică una în alta).
124
Problema 6. Se citesc 3 numere întregi. Câte sunt pare?
Rezolvare. Numărul de valori pare se va reţine în variabila p. Se testează,
pe rând, fiecare număr, iar dacă este par, se adună 1 la p:
Problema 7. Se citesc 3 numere intregi. Câte dintre afirmaţiile de mai jos
sunt adevărate?
toate numerele sunt divizibile cu 3;
două şi numai două sunt pare;
toate numerele sunt strict mai mari decât 10.
Rezolvare. Procedăm la fel ca la programul anterior pentru a vedea dacă
prima condiţie este îndeplinită. Dacă da, se adună 1 la variabila rasp.
Procedeul se repetă pentru condițiile următoare, iar la sfârşit se tipăreşte
conţinutul variabilei rasp:
x = int(input('x = '))
y = int(input('y = '))
z = int(input('z = '))
#variabila in care retin conditiile indeplinite
rasp = 0
#conditia 1
if x%3==0 and y%3==0 and z%3==0:
rasp = rasp+1
#conditia 2
c = 0 #retine cate numere sunt pare
if x%2==0:
c = c+1
125
if y%2==0:
c = c+1
if z%2==0:
c = c+1
if c==2: #testez daca c este egal cu 2
rasp = rasp+1
#conditia 3
if x>10 and y>10 and z>10:
rasp = rasp+1
print('Au fost indeplinite: ',rasp, ' conditii!')
Observație. Pentru a nu scrie iar 3 instrucțiuni if, am folosit operatorul and,
care întoarce True doar dacă sunt adevărate toate cele 3 condiții.
Prioritatea operatorilor % și == este mai mare decât a lui and în Python:
x%3==0 and y%3==0 and z%3==0
Problema 8. Se citesc 4 numere întregi. Să se decidă dacă sunt distincte
(adică nu există două egale între ele).
Rezolvare. Se compară primul număr cu toate celelalte, al doilea cu cele
care îi urmează, al treilea cu al patrulea. Dacă în nici o comparaţie nu
rezultă egalitate, se tipăreşte mesajul corespunzător:
Atenţie la modul în care au fost puse condiţiile!
Puteam scrie și invers, folosind operatorul or, ca mai jos:
if x1==x2 or x1==x3 or x1==x4 or x2==x3 or x2==x4 or x3==x4:
print('Nu sunt diferite!')
else:
print('Sunt diferite!')
126
Problema 9. Se consideră lista1 = [0,1,2,3,4,5,6,7,8,9] și se citește un
număr întreg de la tastatură, x. Afișați dacă valoarea se găsește în listă.
Rezolvare. Folosim if și operatorul in:
Așadar, putem folosi bineînțeles instrucțiunea if pentru a testa dacă
anumite obiecte / valori se găsesc în liste, tupluri, seturi ori dicționare.
6.1.5. Case/switch nu există...
În Python nu a fost implementată o astfel de instrucțiune, precum poate
sunteți obișnuiți din alte limbaje de programare. Deși se poate simula cu
ajutorul funcțiilor, în acest moment avem la dispoziție instrucțiunea if, care
poate fi extinsă de câte ori vrem cu elif, iar la final, eventual cu else.
Exemplul 6.5. Se citește un număr natural între 1 și 9. Afișați numărul citit
folosind cuvinte – pentru 3, vom tipări "trei". Programul este:
127
Am folosit else pentru a prevede situația în care numărul dorit nu se
găsește între 1 și 9. De asemenea, observați că putem scrie și instrucțiunea
imediat după if ori elif, ca anterior, fără a folosi indentarea!
Hmm... dar putem folosi dicționarele! Priviți mai jos:
Dacă numărul de tip int citit se găsește ca și cuvânt cheie în dicționarul
dict1, afișăm imediat valoarea asociată. Dacă nu, ... avem else.
Mai putem folosi și listele! Știm că sunt indexate, deci
am format o listă cu nouă elemente care rețin textul corespunzător pentru
obiectul accesat cu x-1 (indicii sunt de la 0 la 8!). Am impus ca valorea
numerică să fie între 1 și 9 ca și condiție logică pentru if (... clar, puteam
scrie și x>=1 and x<=9) – variantele sunt multiple, programăm cum vrem!
128
6.1.6. Exerciții propuse
Sugestie. Din nou, încercați ca programele să fie user-friendly. Indicați corespunzător ceea
ce cereți ca date de intrare și prezentați datele elegant la ieșire. E fundamental!
1. Se citește o valoare numerică. Să se precizeze dacă este pozitivă sau nu.
2. Se citesc trei valori reale, a,b,c. Să se precizeze dacă ele pot fi laturile
unui triunghi.
3. Se citesc 3 numere intregi. Să se tipărească, dacă există, numărul care
este egal cu suma celorlalte două.
4. Se citeşte x, un număr real. Să se evalueze expresia:
x 2 x 2,
1
F ,
xx 1
,
x 1
pentru x 10;
pentru10 x 20;
pentru x 20.
5. Să se citească 3 numere întregi şi să se tipărească în ordine crescătoare.
6. Fiind date două numere naturale formate din 4 cifre, afișați numărul
care are penultima cifră mai mare.
7. Se dau două numere naturale. Afișați dacă primul se împarte perfect
(este divizibil) cu al doilea.
8. Se citește un număr natural format din două cifre. Suma cifrelor sale
este pară sau nu?
9. Considerăm lista vocalelor englezești:
vocale = ['a','e','i','o','u']
Realizați câte un program pentru fiecare cerință de mai jos:
a) Se citește o singură literă de la tastatură. Precizați dacă este vocală
sau consoană.
b) Fiind citit un șir de caractere, precizați dacă primul și ultimul
caracter sunt vocale sau nu.
129
6.2. Instrucțiunea repetitivă for
În multe cazuri este necesar ca o instrucţiune să fie executată de mai multe
ori. Cum am procedat până acum? Am scris instrucţiunea de câte ori a fost
necesar. Aceasta nu este o soluţie acceptabilă. Să ne imaginăm că o
instrucţiune trebuie executată de 10000 de ori.
Vom folosi instrucţiunile repetitive, iar acestea sunt: for şi while. De câte
ori şi în ce condiţii? Vom vedea... în cele ce urmează.
6.2.1. Forma generală
Am precizat faptul că Python este puternic orientat pe obiecte, iar aproape
orice element este un obiect. Am studiat anterior șirurile de caractere și
colecțiile de date (liste, tupluri, seturi și dicționare), iar acum este
momentul să navigăm printre componentele acestora. Vom folosi for,
care are forma generală ca cea de mai jos:
for variabila in colectie_de_obiecte:
...set_de_instrucțiuni
Putem citi astfel - pentru fiecare obiect din cadrul colecției, efectuăm un
set de instrucțiuni de prelucrare. Să analizăm mai multe exemple...
Exemplul 6.6. Să presupunem că avem o listă și dorim să afișăm toate
elementele acesteia. Nimic mai simplu:
În acest caz, instrucțiunea print din cadrul for a fost
executată de 5 ori, pentru fiecare element în parte.
La fiecare pas, variabilei x i se atribuie elementul care urmează pentru a
putea fi folosit în interiorul setului de instrucțiuni.
130
Exemplul 6.7. Putem afișa doar numerele pare dintr-o listă:
Fiecare element citit este afișat doar dacă este îndeplinită condiția
instrucțiunii if. Atenție la indentare!
Mai mult, putem de exemplu efectua suma elementelor impare. Vom folosi
încă o variabilă care va reține suma:
ori ... putem să folosim clauza else și afișăm suma numerelor impare și cea
a celor pare:
Aici am folosit două variabile care rețin cele două sume (inițiale, 0).
131
Exemplul 6.8. Să afișăm toate caracterele unui șir!
Exemplul 6.9. Afișăm toate caracterele șirului care sunt vocale folosind o
listă separată de test. Dacă elementul curent se găsește în lista vocalelor,
atunci este afișat:
Exemplul 6.10. Afișăm toate perechile unui dicționar (deși neordonat, este
indexat după cuvinte cheie), ca mai jos:
Putem tipări și altfel perechile
de valori, folosind doar o singură
dată apelul funcției print:
Interesant, nu?
132
Folosind parantezele pătrate, obținem valorile asociate cheilor, fără a apela
la metoda get:
Obs. Variantele sunt multiple deoarece avem multe opțiuni pentru fiecare
tip de obiect. Putem folosi și alte metode precum values() și items().
Documentați-vă pe Internet despre ele!
6.2.2. Funcția range(). Forma clasică pentru for
Am folosit instrucțiunea for pentru a naviga secvențial printre toate
elementele unui obiect / colecție de date. Adesea este necesar să repetăm
un set de instrucțiuni de un anumit număr de ori, similar programării
clasice în Pascal/C++/Java, etc.
Analizați programul de mai jos:
Funcția range(final) primește un număr întreg pozitiv ca
parametru și generează o secvență de numere, de la 0 până
la final-1. La fiecare pas este folosit un element, de la
stânga la dreapta, reținut de variabila n, pentru prelucrare.
Forma generală a funcției range este
range(inceput,final,pas)
Bineînțeles, inceput (implicit, 0) și pas (implicit, 1) sunt opționale.
Dacă scriem range(1,5), vor fi afișate numerele de la 1 la 4, iar dacă folosim
range(1,10,2), cifrele impare de la 1 la 9 (de la 1, din doi în doi).
Analizați în continuare câteva probleme rezolvate.
133
6.2.3. Probleme rezolvate
Problema 1. Se citeşte n (număr natural). Se cere să se efectueze suma
primelor n numere naturale. Exemplu: n=3, S=1+2+3=10.
Rezolvare. Cum procedăm? Este posibil să cunoaşteţi formula prin care se
obţine suma primelor n numere naturale:
Sn
n (n 1)
2
Dacă aplicăm această formulă problema devine foarte uşoară. Întrucât
exemplul este dat pentru învăţarea instrucţiunii for, presupunem că nu o
cunoaştem.
Astfel, precum am mai lucrat, vom aduna, pe rând, numerele 1, 2, ..., n la
conţinutul unei variabile s:
Am scris parametrii corespunzători pentru funcția range, astfel încât să fie
generată o secvență numerică de la 1 la n.
Super! Testați acum cu n=10000 sau n=1000000:
134
Problema 2. Să se calculeze suma: S=0,1+0,2+.
0,9.
Rezolvare. Avem 9 paşi. La fiecare pas se adună un număr. Rezultatul este
de tip float, evident. Este adevărat, variabila de ciclare nu poate lua decât
valori întregi. Recurgem la următorul artificiu: vom considera o variabilă
i care ia valori de la 1 la 9. La fiecare pas se adună valoarea reală i/10.
Când i este 1, se adună 1/10=0,1, când i este 2 se adună 2/10=0,2, ş.a.m.d.
iar rezultatul în consola interactivă este:
Problema 3. Se citeşte n, număr natural. Se cere să se calculeze suma:
S 11 2 1 2 3 1 2
n
Rezolvare. Ce avem de făcut? Observăm că avem n paşi. La pasul i se adună
valorea 1*2 *i, iar i este cuprins între 1 şi n.
Pasul 1. Se adună 1
Pasul 2. Se adună 1*2
.......................
Pasul n. Se adună 1*2*3*. *n
Dacă la problemele anterioare valoarea care se adună se obţine uşor, aici
este puţin mai complicat. De ce? Pentru că şi ea trebuie calculată. Cum o
calculăm? Folosim un nou ciclu? În nici un caz. Se poate mai simplu.
Observăm faptul că singura diferenţă dintre valorile care se adună la pasul i
şi pasul i+1 este că cea adunată la pasul i+1 se obţine înmulţind cu i+1
valoarea adunată la pasul i. Exemplu. La pasul 2 se adună 1*2. La pasul 3 se
adună 1*2*3, adică (1*2)*3. Să notăm cu p valoarea care se adună la
fiecare pas. Iniţial p este 1. La pasul i+1, înainte de a fi adunată, valoarea p
se înmulţeşte cu i+1. Să urmărim programul:
135
Iniţial, s=0; p=1.
Pasul 1. p:=p*1; p=1*1=1; s:=s+p; s=0+1=1;
Pasul 2. p:=p*2; p=1*2=2; s:=s+p; s=1+2=3;
Pasul 3. p:=p*3; p=2*3=6; s:=s+p; s=3+6=9;
...
Problema 4. Se citeşte un număr natural. Se cere să se decidă dacă este
prim sau nu. Exemplu. Citim 7. Acesta este număr prim. Citim 9. Acesta nu
este număr prim.
Rezolvare. Reamintim faptul că un număr natural este prim dacă şi numai
dacă singurii divizori (numere naturale) sunt 1 şi numărul testat. Astfel: 7
este prim pentru că singurii săi divizori sunt 1 şi 7, iar numărul 9 nu este
prim pentru că 3 este divizor al lui.
Ce trebuie să facem? Să testăm, pe rând, toate numerele naturale care pot
fi divizori ai numărului citit (nr), iar dacă găsim unul care este divizor
înseamnă că numărul nu este prim. Care sunt numerele pe care le testăm?
Numărul 1 este divizor pentru orice număr, deci nu trebuie testat. Începem
cu 2. Ultimul număr testat va fi nr//2. De ce? Exerciţiu. Cunoaşteţi o
metodă care permite să se testeze şi mai puţine numere?
136
Observăm că am folosit o variabilă logică numită divizor. Aceasta este
iniţializată cu valoarea False. Dacă dintre numerele testate există cel puţin
un divizor, variabila va lua valoarea True, altfel rămâne cu valoarea iniţială.
Cineva ar putea întreba? Dar dacă numărul are mai mulţi divizori, ce
valoare va reţine variabila divizor? Atunci când a fost găsit primul divizor,
variabila divizor va reţine True. Dacă am mai găsit unul, variabilei i se
atribuie din nou True. Important este faptul că la sfârșit aceasta va avea
valoarea True.
Observație. Procedeul este des folosit în programare. O variabilă are o
anumită valoare inițial. Dacă la toate testele care se fac nu se îndeplineşte
o anumită condiţie, variabila rămâne cu valoarea iniţială. Altfel, aceasta va
reţine o nouă valoare. În final, se va testa valoarea reţinută de variabilă.
Pentru exemplu, am lucrat pornind de la ipoteza că numărul citit este prim.
În cazul în care există un divizor (dintre cei căutaţi), numărul nu va
fi prim.
Aţi observat faptul că algoritmul are o deficienţă? Dacă am găsit deja un
divizor, este clar faptul că numărul nu este prim. Ce rost are să fie testaţi
ceilalţi posibili divizori? De exemplu, dacă numărul citit este 100. Primul
număr testat este 2. Acesta este divizor. Din acest moment se poate trage
concluzia că numărul citit nu este prim. Cu toate acestea, algoritmul
testează toate numerele până la 50 Ce avem de făcut pentru a remedia
deficienţa arătată? Deocamdată lăsăm problema deschisă.
Vom reveni asupra ei curând.
Problema 5. Se citesc n numere întregi. Se cere să se tipărească cel mai
mare număr citit. Exemplu: avem n=4, iar numerele sunt -7, 9, 2, 3, se
va tipări 9.
Rezolvare. Gândim așa:
-
inițial, cel mai mare număr este -7;
9>-7, deci cel mai mare număr este 9;
2<9, deci cel mai mare număr rămâne 9;
3<9, cel mai mare număr rămâne 9.
Am parcurs integral valorile şi cel mai mare număr rămâne 9. Vă daţi
seama că raţionamentul de mai sus rămâne valabil pentru un şir de n
numere (n, număr natural oarecare).
137
Şi acum, algoritmul:
Pasul 1. O variabilă, numită max va reţine primul număr.
Pasul 2. Dacă al doilea număr>max, atunci max va reţine al doilea număr.
Pasul 3. Dacă al treilea număr>max, atunci max va reţine al treilea număr.
...
Pasul n. Dacă ultimul număr>max, atunci max va reţine ultimul număr.
Observăm că nu este necesar să reţinem, la un anumit moment dat, decât
un singur număr (cel analizat), precum şi maximul dintre cele anterioare:
Priviți consola pentru datele ca exemplu.
Concluzie. Toate exemplele au arătat faptul că instrucţiunea for împreună
cu range se utilizează dacă sunt îndeplinite condiţiile următoare:
o secvenţă se repetă;
se cunoaşte înaintea intrării în secvenţă de câte ori trebuie să fie
executată secvenţa.
A doua condiţie este esenţială.
Exemplu: pentru suma primelor n numere naturale, la citirea lui n ştiam de
câte ori se repetă instrucţiunea în care numărul este adunat la conţinutul
variabilei s.
138
6.2.4. Citirea colecțiilor de date de la tastatură
În ultimul exemplu am văzut că folosind instrucțiunea for, citim un anumit
număr de valori (finit, reținut de n) introduse de utilizator.
Exemplul 6.11. Putem citi valorile unei liste pe care să le reținem într-o
colecție de date a programului nostru (obiectul lista):
Inițial, lista este vidă. La fiecare pas, se adaugă un element citit folosind
metoda append(), deja prezentată. La final, se afișează.
Puteam scrie mai elegant instrucțiunea de adăugare așa:
lista.append(input('elementul ' + str(x)+ ' = '))
iar citirea datelor este acum faină:
Dacă dorim ca elementele listei să conțină doar numere, folosim conversia
explicită, spre exemplu spre numere reale (clasa float):
lista.append( float(input('elementul ' + str(x)+ ' = ')) )
139
6.2.5. Mai mult despre user-friendly
În orice domeniu lucrați ori dacă sunteți elev sau student, programele
voastre trebuie să citească și să afișeze informațiile facil, cu indicații și
informații ajutătoare.
În spate, în cod, este programul vostru – prelucrarea! Dar cel ce utilizează
programul are nevoie DOAR de intrări și ieșiri elegante, sugestive.
Exemplul 6.12. Se citește și se afișează un dicționar:
Am executat o dată programul cu n = 3, deci trei perechi:
140
Eu am modificat programul anterior astfel:
Puteți să realizați unul similar, după bunul plac?
141
6.2.6. Exerciții propuse
1. Ionel a depus la bancă suma de S lei. Dobânda este p% pe lună.
Ce sumă are Ionel după k luni? Programul va citi S, p, k şi va afişa
suma cerută.
2. Se citeşte un număr natural. Se poate descompune sub formă de
pătrate? Exemplu: se citeşte 13. Răspuns: Da. 32+22=13.
3. Se citeşte n, număr natural. Să se evalueze expresiile de mai jos:
1
E 1 1 ... 1
;
1 2 ...n
1 1 2 1 2 3
E 1 1 3 1 3 5 ... 1 3 ... (2n 1);
E E1 E2 ... En ,
unde
Ei
1
1
1
.
...
1 2 ...(i 1)
1 2 1 2 3
4. Tipăriţi toate numerele prime aflate între două numere naturale citite.
5. Se citesc, pe rând, n numere naturale. Se cere produsul celor care sunt
diferite de 0 și pare.
6. Se citesc, pe rând, n numere reale. Să se afişeze suma maximă care se
poate forma cu ajutorul lor.
7. Se citesc, în ordine, cele n cifre ale unui număr natural. Se cere să se
construiască şi să se afişeze numărul format. Exemplu: se citesc 6, 7, 3.
Se va afişa 673.
8. Proiect. Se citesc două mulțimi, reținute de variabilele A și B, fiecare cu
n și m elemente. Să se afișeze reuniunea, intersecția și diferențele celor
două mulțimi, precum și care are mai multe elemente.
Notă. Programul trebuie să fie user-friendly. Ca toate, de altfel...
142
6.3. Instrucțiunea repetitivă while
6.3.1. Forma generală
Ca şi for, instrucţiunea while este repetitivă și subordonează un set de
instrucţiuni. Forma generală este cea de mai jos:
while expresie_logică_adevărată:
set_de_instrucțiuni
Principiul de executare este:
Pasul 1. Se evaluează expresia logică. Dacă se obţine valoarea True, se
trece la pasul 2, altfel executarea instrucţiunii se încheie.
Pasul 2. Se execută setul de instrucțiuni, apoi se trece iar la pasul 1.
Exemplul 6.13. Se citeşte n, număr natural. Să se calculeze suma primelor n
numere naturale. Această problemă a fost rezolvată şi cu ajutorul
instrucţiunii for. Să vedem cum folosim while:
instrucțiune compusă, subordonată, indentată
Valoarea iniţială a variabilei i este 1. Atât timp cât i este mai mic sau egal cu
n citit, se execută instrucţiunea compusă (subordonată instrucţiunii while).
Aceasta cuprinde instrucţiunea prin care valoarea lui i este adunată valorii
reţinute de suma şi instrucţiunea prin care se adună 1 valorii reţinute de i.
Observație. Este recomandat să folosim instrucţiunea while atunci când
sunt îndeplinite simultan două condiţii:
setul de instrucțiuni se execută (de câte ori este cazul) numai dacă
este îndeplinită o anumită condiţie;
în momentul în care se intră în secvenţa repetitivă nu se ştie de câte
ori aceasta se va executa.
143
6.3.2. Probleme rezolvate
Problema 1. Se citeşte un număr natural n, diferit de 0. Să se tipărească
suma cifrelor sale. Exemplu. Dacă se citeşte 248, se va tipări 14 (14=2+4+8).
Rezolvare. Această problemă a mai fost rezolvată de voi. Numai că, în acel
caz, am ştiut de la început numărul de cifre pe care le are numărul.
Cum facem acum când nu ştim acest lucru? Izolăm ultima cifră (pe care o
adunăm la o variabilă suma, cu valoarea iniţială 0), apoi obţinem numărul
fără ultima cifră. Aceste operaţii se efectuează repetitiv, numai dacă
numărul este diferit de 0. Programul este prezentat mai jos:
Simplu și precis, folosind while!
Problema 2. Se citeşte un număr natural n. Să se tipărească numărul
obţinut prin inversarea poziţiilor pe care le ocupă numărul citit.
Exemplu. Dacă citim n=248, se va tipări 842.
Rezolvare. Să considerăm două numere: al doilea număr a fost obţinut din
primul prin adăugarea la sfârşit a unei cifre (456 şi 4563). Avem relaţia:
4563 = 45610 + 3
Evident, relaţia este adevărată pentru oricare două numere naturale care
îndeplinesc condiţia de mai sus. Este clar că numărul inversat va începe cu
ultima cifră a numărului citit. Să presupunem că am citit 248. Vom construi
numărul inversat astfel:
8=010+8
(8 este ultima cifră a numărului citit şi rămâne 24)
84=810+4
(4 este ultima cifră a numărului rămas şi se obţine 2)
842=8410+2 (2 este ultima cifră a numărului 2 şi se obţine 0)
Analizaţi programul rezultat:
144
Am efectuat un test în consola interactivă:
Problema 3. Se citeşte un număr natural n. Se cere să se decidă dacă este
prim sau nu.
Rezolvare. Această problemă a fost rezolvată cu ajutorul instrucţiunii for.
Algoritmul folosit avea un neajuns. În cazul în care se găseşte un divizor,
se caută mai departe, fără nici un rost, alţi divizori.
Cum eliminăm neajunsul amintit? Prin utilizarea instrucţiunii while, care
e indispensabilă în astfel de situaţii (în care nu cunoaştem de câte ori se
repetă secvenţa).
Observaţi modul în care am procedat:
se generează primul posibil divizor (2);
pentru a executa instrucţiunea compusă subordonată lui while,
acesta trebuie să îndeplinească simultan două condiţii:
- să fie mai mic decât jumătatea numărului;
- să nu dividă numărul.
De ce toate acestea? Pentru că instrucţiunea subordonată lui while
generează următorul divizor. Cu alte cuvinte, ca să generăm următorul
posibil divizor trebuie ca să existe un număr, mai mare decât cel analizat,
care are şansa să fie divizor şi numărul analizat să nu fie divizor.
Este demn de remarcat "trucul" folosit. Testul dacă un număr este sau nu
divizor nu se face în instrucţiunea subordonată while, ci chiar în expresia
logică a sa... analizați programul!
145
În aceste condiţii, cum decidem dacă numărul este sau nu prim? Simplu.
Dacă s-au testat toate numerele posibile înseamnă că numărul este prim.
Altfel, înseamnă că a fost găsit un divizor, caz în care bineînțeles că
numărul nu este prim.
Rulăm în consolă câteva exemple...
Problema 4. Se citesc numerele naturale n1 şi n2. Să se calculeze produsul
lor, fără a utiliza operatorul de înmulţire.
Rezolvare. Algoritmul se bazează pe faptul că înmulţirea este o adunare
repetată. De exemplu, dacă citim 3 şi 4, calculăm produsul astfel
3+3+3+3=12 (am adunat de 4 ori).
Adunarea repetată se face utilizând instrucţiunea while. Poate că vă veţi
întreba de ce am folosit while, atât timp cât, este evident, numărul de
executări ale instrucţiunii subordonate while este cunoscut de la bun
început. Aşa este! Dar dacă folosirea instrucţiunii while nu este indispensabilă, nu înseamnă că nu avem voie să o folosim...
146
În programul următor se vede cum am procedat:
Atenţie! Spre deosebire de cazul
în care folosim for, gestiunea
variabilei de ciclare o facem
noi (i=i+1)!
Problema 5. Se citesc două numere naturale n1 şi n2. Se cere să se
calculeze câtul şi restul împărţirii întregi ale celor două numere, fără a
utiliza operatori de împărţire.
Rezolvare. Cum procedăm? Aşa cum înmulţirea se poate face prin adunare
repetată, tot aşa împărţirea se poate face prin scădere repetată.
Din deîmpărţit (n1) se scade (dacă este posibil - dacă deîmpărţitul este mai
mare sau egal cu împărţitorul) împărţitorul (n2) şi la fiecare scădere se
adună 1 la cât (iniţial 0).
Când ne oprim? Atunci când valoarea rămasă (în urma scăderilor repetate
din deîmpărţit a împărţitorului) este mai mică decât împărţitorul (dacă se
scade împărţitorul se obţine o valoare negativă).
Exemplu. Pentru n1=10 şi n2=3:
10-30; n1=10-3=7; c=1;
7-30; n1=7-3=4; c=2;
4-30; n1=4-3=1; c=3;
1-3<0; se iese din ciclu se afişează câtul (3) şi restul 1.
Programul este următorul:
147
Câteva rezultate...
6.3.3. Exerciții propuse
1. Se citeşte un număr natural. Să se afişeze numărul de cifre din care
acesta este format. Exemplu: se citeşte 1078, se afişează 4.
2. Să se citească câte un număr întreg de la tastatură până se introduce 0.
3. Proiect. Revenim la dicționar. Modificați programul din secțiunea
anterioară, în sensul că se va crea o aplicație care citește de la tastatură
perechi de date care vor forma un dicționar. În acest caz, numărul de
elemente este necunoscut și la discreția utilizatorului. Când introduce
cheia zero, citirea datelor se oprește și se afișează dicționarul format.
Atenție din nou la user-friendly! Orice program creat trebuie să aibă
datele de intrare și de ieșire prezentate cu indicații și atractiv!
148
6.4. Clauzele break și continue
6.4.1. Clauza break
Dacă ne dorim ieșirea forțată dintr-un ciclu repetitiv, fie for ori while,
putem folosi break.
Exemplul 6.14. Presupunem că avem o listă formată din mai multe șiruri de
caractere (clasa str). La întâlnirea șirului "d", ciclul se oprește:
Atunci când variabila x a primit valoarea elementului "d", condiția din
cadrul if a fost îndeplinită, iar break executată – ciclul for s-a încheiat
imediat, deși mai erau de evaluat elementele din listă și de tipărit valori.
6.4.2. Clauza continue
Ne putem dori câteodată ca pentru anumite valori să nu se execute tot
setul de instrucțiuni subordonate ciclului repetitiv (adică iterația curentă):
În acest caz, atunci când a fost întâlnit elementul "d", acesta nu a mai fost
afișat, însă s-a trecut la iterația următoare a ciclului for (mai exact, funcția
print nu a mai fost executată).
Am întâlnit anterior situații când aceste clauze pot fi utile.
149
La voia întâmplării...
"Ce bine că eşti, ce mirare că sunt!" (Nichita Stănescu)
7.1. Numere aleatoare
Mulți dintre voi poate ați jucat la Loto 6/49, unde nu putem prezice acele
șase numere valoroase... cu toată statistica din lume, iar doar o întâmplare
fericită !!! ne poate conduce la ghicirea lor, având în vedere că sunt
13.983.816 variante posibile. Hazardul!
De altfel și jocurile pe calculator conțin numere la întâmplare, numite
aleatoare, astfel încât de fiecare dată pare că totul este altfel, un nou
scenariu, un nou set de culori, bile ori inamici care apar din poziții diferite.
Un număr aleator este în esență unul care nu poate fi prezis de utilizator.
De fapt, în spate există un generator (o funcție) care ne oferă la fiecare
apelare un astfel de număr. Ele sunt pseudo-aleatoare, în sensul că sunt
create în urma unor calcule matematice complexe.
Notă. Website-ul random.org folosește zgomotul atmosferic și calcule
complexe pentru a genera numere aleatoare reale, iar pagina este folosită
în foarte multe domenii de activitate.
7.2. Cum le putem genera în Python?
7.2.1. Importarea primului nostru modul - random
Setul de funcții pe care îl conține implicit limbajul Python nu este foarte
mare, însă așa cum am precizat la începutul cărții, acesta este extins prin
module (colecții de funcții, numite în alte limbaje, biblioteci).
Unul dintre acestea este random, creat special pentru a genera numere
aleatoare. Pentru a putea folosi funcțiile sale, la începutul programului vom
scrie "import random", care încarcă modulul și ne oferă acces la el:
150
Observații importante!
1.
Am importat modulul random, apoi am tipărit cinci numere aleatoare
folosind instrucțiunea for pentru iterații.
2.
Pentru a apela o funcție din cadrul unui modul, scriem:
nume_modul.funcția_dorită
3.
Mai sus am folosit chiar funcția random(), care generează un număr
real, de tip float, între 0.0 și 1.0 – funcția nu acceptă parametri.
Exemplul 7.1. Bineînțeles, nu ne prea ajută aceste numere... Cum putem
însă afișa numere aleatoare întregi între 0 și 100? Sau între 0 și 10000?
Simplu, folosind înmulțirea și rotunjirea (sau conversia
explicită spre int):
Dacă a fost generat 0.483421... Înmulțindu-l cu 100, se obține 48.3421...,
care apoi convertit ori rotunjit spre un număr întreg, devine 48.
151
Exemplul 7.2. Cum putem genera numere întregi între 20 și 70?
Putem tipări, precum anterior, numere între
0 și 50. Doar adunăm 20 pentru fiecare număr în
parte apoi:
7.2.2. Funcția randint
Modulul random conține o serie consistentă și avansată de funcții pentru a
genera numere aleatoare. Una dintre acestea ne scutește de calculele
anterioare pentru a obține numere întregi.
Exemplul 7.3. Funcția randint(început,sfârșit) întoarce un număr aleator
întreg cu semn (deci tipul int) din intervalul specificat de parametri:
Mai jos avem un set de rezultate:
random.randint(0,100)
random.randint(-10000,10000)
152
7.2.3. Funcția choice
Putem alege unul dintre obiectele reținute de o listă, un tuplu sau un șir de
caractere, folosind funcția choice(obiect). Funcția întoarce la întâmplare un
element din cadrul obiectului.
Exemplul 7.4. Se consideră o listă care conține anumite componente. Vom
afișa aleator doar două dintre ele:
Am rulat apoi programul de 3 ori:
Exemplul 7.5. Afișăm aleator un caracter din cadrul unui șir:
Testați programul... va fișa aleator poate "M", "j", "i", "e", "r", etc.
De fapt, unul dintre caracterele prezente în șir.
153
7.2.4. Funcția shuffle – amestecarea
Să presupunem că avem o listă și ne dorim să o amestecăm, precum un
pachet de cărți de joc nou, astfel încât ordinea implicită a elementelor să
fie modificată aleator.
Putem folosi funcția shuffle(variabilă_obiect), care primește ca
paramentru un obiect de tip listă, tuplu sau șir de caractere. Această
funcție nu întoarce nimic (None), ci are efect direct asupra obiectului trimis
ca parametru.
Exemplul 7.6. Priviți programul următor:
Rețineți faptul că folosind această funcție, alterăm definitiv obiectul inițial.
Bineînțeles că amestecarea va fi diferită la fiecare altă rulare a programului.
7.2.5. Funcția seed – sămânța întâmplării
Am precizat de la început faptul că numerele sunt pseudo-aleatoare, adică
sunt generate în urma unor calcule matematice complexe. Funcția
seed(nr_intreg_optional)
este utilă atunci când dorim să inițializăm generatorul de la aceeași valoare
– potrivită pentru testarea programelor noastre. Dacă folosim același
argument de mai multe ori, vom obține de fiecare dată o serie identică de
numere aleatoare. Interesant, nu?!?
154
Exemplul 7.7. Folosim metoda seed pentru a tipări cinci numere aleatoare,
iar ca parametru vom specifica, să spunem, 17:
Rulăm programul de două ori și obținem:
Important. Am specificat prin seed de fapt sămânța întâmplării, un loc de
pornire pentru numerele aleatoare create ulterior. Dacă nu folosim funcția
seed, ori o apelăm fără parametrul opțional, valoarea implicită a
argumentului este timpul curent al sistemului, a.î. de fiecare dată vom avea
numere diferite și la întâmplare.
De ce este utilă? Să spunem că realizăm un joc și folosim numere
aleatoare. Pentru a putea evalua funcționarea programului, modul
întâmplător indus, analiza valorilor obținute, avem nevoie ca de fiecare
dată, în regim de test, să repornim generatorul, astfel încât la executarea
programului, numerele să fie la fel. Bineînțeles că la final, când totul
funcționează corect, ștergem apelul funcției seed...
Suficientă teorie!
Să trecem la crearea unor jocuri simple, clasice...
155
7.3. Primele jocuri în Python
Când vă spune cineva că în 2-3 luni veți învăța să programați jocuri precum
Clash Royale sau Fortnite, ori că veți fi expert în Python ... faceți stânga
împrejur și fugiți. :) Deși nu este imposibil, deoarece imaginația,
creativitatea și inteligența nu au limite, precum bine știm, în spatele unor
jocuri de succes stau armate de programatori, graficieni, proiectanți și
testeri, echipe întregi care le susțin zi de zi. Experiența are un rol esențial în
programare – înveți și evoluezi zi de zi. Treptat și cu multă răbdare!
Cu toate acestea, oricare ar fi nivelul la care se dezvoltă o aplicație,
principiul este cam același – utilizatorul trebuie să fie uimit de fiecare dată,
provocat să joace din nou, să greșească, să gândească, să se adapteze,
să dobândească reflexe ori strategii noi de abordare, ș.a.m.d.
În continuare vom încerca să realizăm câteva mici aplicații / jocuri care
trebuie să fie cât mai atractive și interesante pentru cei ce le vor folosi –
atenție din nou la intrări și ieșiri elegante!
7.3.1. Ghicește numărul!
Programul generează un număr aleator ascuns între 1 și 100, iar utilizatorul
este invitat să ghicească acest număr. În mod repetat, dacă numărul
nu este nimerit de la tastatură, este afișat un mesaj corespunzător ca
indiciu - "mai mic" sau "mai mare".
Rezolvare. Vom genera numărul aleator – e simplu. Apoi, nu știm de câte
ori se va executa ciclul repetitiv, așadar vom folosi cu siguranță
instrucțiunea while. Expresia logică a sa e evidentă – numărul introdus este
egal sau nu cu cel ales la întâmplare. Mai rămâne de adăugat un if... în
cazul în care numărul nu a fost potrivit! Să vedem programul:
import random
numar = random.randint(1,100)
ghicit = int(input())
while numar != ghicit:
if ghicit > numar: print("Este mai mic!")
else: print("Este mai mare!")
ghicit = int(input())
print("Felicitari, ai ghicit numarul!")
156
Obs. Prima încercare (citire de la tastatură) este efectuată înaintea ciclului
while deoarece trebuie să avem un număr inițial cu care să comparăm în
expresia logică. Dacă numărul a fost ghicit din prima, se afișează direct
mesajul de felicitare final. Dacă nu, se citește un nou număr din while.
Eu am mai stilizat puțin programul, precum mai jos:
Exercițiu. Adăugați o variabilă care reține și afișează la final numărul de
încercări efectuate de utilizator!
157
7.3.2. Tabla înmulțirii
Ne propunem să realizăm un test format din 10 operații de înmulțire cu
numere naturale între 1 și 10. La fiecare operație va fi afișat un mesaj de
validare a rezultatului, iar la final, nota obținută!
Rezolvare. De această dată, vom avea nevoie de două numerele aleatoare
generate la fiecare pas (reținute în variabilele n și m) și deoarece știm
numărul total de iterații, vom folosi instrucțiunea repetitivă for. Analizați
programul (fără stilizare):
import random
ok = 0
for x in range(10):
n = random.randint(1,10)
m = random.randint(1,10)
rez = n * m
rasp = int( input(str(n)+"*"+str(m)+"=") )
if rasp == rez:
print('Corect!')
ok = ok + 1
else:
print('Incorect!')
print('Nota finala este',ok,"/10!")
Alăturat este prezentată o rulare a
programului nostru – voit, am greșit de
trei ori, iar la final nota a fost pe măsură!
Variabila ok reține numărul de răspunsuri
corecte introduse de utilizator.
Atenție la funcția input(), care poate
primi ca parametru un șir de caractere.
Am folosit conversia explicită spre tipul str
pentru cele două numere generate,
astfel încât operatorul + să poată fi folosit.
Exercițiu. Corect ar fi ca nota să înceapă
de la 1, iar la fiecare răspuns să fie
adunate 0.9 puncte. Atenție la rotunjiri,
știți deja funcția! Efectuați modificările!
158
Și de această dată vă propun programul user-friendly considerat de mine:
import random
#elemente de prezentare
print('----------------------------------- ')
print('Tabla inmultirii - test de evaluare')
print('----------------------------------- ')
print('Efectuati corect cele 10 operatii!')
print('----------------------------------- ')
print('Apasa o tasta pentru a incepe... ')
input()
#incepem testul...
ok = 1
for x in range(10):
print("Operatia",x+1,"din 10:")
n = random.randint(1,10)
m = random.randint(1,10)
rez = n * m
rasp = int(input(str(n)+" * "+str(m)+" = "))
if rasp == rez:
print('Corect!')
ok = ok + 0.9
else:
print('Incorect!',str(n)+" * "+str(m)+" =", n*m)
print(' ----------- ')
#la final, evaluez rezultatele
if ok<5:
print('Ai obtinut', round(ok),'! Mai invata .. ')
elif ok<8:
print('Ai obtinut', round(ok),'! Atentie... ')
elif ok<10:
print('Ai obtinut', round(ok),'! Aproape perfect .. ')
else:
print('Zece! Felicitari!')
Am prezentat rostul programului și ceea ce are de făcut utilizatorul, apoi la
fiecare pas am afișat elegant la ce operație curentă se află, precum și cazul
în care a greșit (îi arăt rezultatul corect – scopul este de a învăța tabla
înmulțirii). La final, am afișat un mesaj corespunzător în funcție de notă!
Să vedem cum arată acum...
159
160
Obs. Forma de prezentare a unui program pentru utilizator este esențială.
Chiar dacă programul este genial, persoana nu știe care este rolul
programului, ce cod este în spate, cum să se descurce ori să opereze datele
inițial. Așadar, la fiecare pas, trebuie îndrumat corespunzător.
De asemenea, special am introdus funcția input() la început (nu folosim
valoarea introdusă la nimic), care are simplul rol de a pregăti utilizatorul,
de a-i oferi posibilitatea să își tragă sufletul și să decidă când începe testul
de evaluare. Aceste aspecte sunt foarte importante!
PROIECTE PROPUSE
1. Modificați programul astfel încât să se efectueze operații de adunare cu
numere între 1 și 100.
2. Puteți crea un program care să ofere ca operații de adunări și scăderi,
similare celui anterior, în mod aleator?
Indicație. Cred că aveți nevoie de un nou număr aleator. Dacă e zero, ofer
adunarea, iar dacă e unu, scăderea.
3. Realizați un program care oferă utilizatorului posibilitatea să aleagă
operația – adunare, scădere ori înmulțire (mai exact, un mic meniu).
În funcție de valoarea introdusă, afișați un test format din zece întrebări.
Nu e atât de complicat... :) sunt doar mai multe instrucțiuni.
7.3.3. Am greșit ceva... cum ieșim forțat din program?
Să spunem că în timp ce testăm, am detectat o eroare ori vrem să ieșim pur
și simplu din programul curent rulat de consolă:
Mai simplu, apăsăm combinația de taste Ctrl + C.
161
Interpretorul Python ne oferă o excepție de tip KeyboardInterrupt, adică
programul a fost întrerupt de la tastatură:
De asemenea, putem merge în editorul de cod, acolo unde scriem
programul și putem apăsa tasta F5. Executarea curentă din consolă se va
încheia imediat și se pornește din nou una nouă (vezi indicația Restart...):
În cazul meu, programul se numește tabla_inmultirii.py.
De multe ori am tăiat imaginea pentru a putea încăpea în aceste pagini,
care au doar 13cm lățime...
7.3.4. Spânzurătoarea - țări din Uniunea Europeană!
Cine nu a jucat spânzurătoarea? Știm numărul de caractere cu care este
format cuvântul, avem un număr limitat de încercări și ghicim literele!
În acest paragraf voi proceda altfel. Vă voi arăta pas cu pas cum aș gândi eu
programul în Python. Deci, să începem!
162
1. Primul lucru care îmi vine în minte este să mă documentez pe Internet
despre țările care fac parte din Uniunea Europeană. Am aflat repede
(acestea sunt în număr de 27) și voi forma o listă care să le rețină pe toate:
tari = ['AUSTRIA', 'BELGIA', 'BULGARIA',
'CIPRU', 'CEHIA', 'CROATIA', 'DANEMARCA', 'ESTONIA',
'FINLANDA', 'FRANTA', 'GERMANIA', 'GRECIA', 'UNGARIA',
'IRLANDA', 'ITALIA', 'LETONIA','LITUANIA',
'LUXEMBURG', 'MALTA', 'OLANDA', 'POLONIA','PORTUGALIA',
'ROMANIA', 'SLOVACIA', 'SLOVENIA', 'SPANIA', 'SUEDIA']
Nu am folosit diacritice și toate sunt cu majuscule. Programul ar fi un pic
mai complicat... Am testat în consolă cu print și len, este scris corect.
2. Bineînțeles, programul va alege o țară în mod întâmplător din lista de
mai sus, deci vom folosi funcția choice din modulul random:
import random
tara = random.choice(tari)
print(tara)
Mai tot timpul testez să văd dacă este corect, deci instrucțiunea print a fost
scrisă pentru mine, temporar, ca să verific dacă e ok:
Este aleasă la întâmplare o țară (mai exact, un șir de caractere) din listă.
Șterg acum instrucțiunea print și secțiunea de cod rămâne:
import random
tara = random.choice(tari)
De reținut este faptul că variabila tara conține răspunsul.
3. La început, jucătorul primește clasic un șir de caractere "_" (underline) cu
lungimea cuvântului respectiv, așadar toate caracterele sunt ascunse.
Verific puțin în consolă și observ un neajuns:
163
Am încercat să tipăresc 3 caractere consecutive și apare doar o linie
continuă. Pentru mai multă ușurință, vom folosi caracterul "–" (minus).
Lungimea variabilei tara o putem obține imediat cu len și formăm secvența
care va fi afișată inițial de program:
rasp = '-' * len(tara)
print('SPANZURATOAREA')
print('Ghiceste tara din UE!')
print(rasp)
Apoi, am afișat cerința programului:
Totul e ok.
4. Mă gândesc la numărul de greșeli pe care le poate face jucătorul.
Era vorba de cap, corp, brațe și picioare – în total de 6 ori. La a șasea
greșeală, jocul se va termina. Nu știu de câte ori greșește utilizatorul, deci
voi folosi instrucțiunea while, care va avea ca și condiție g < 6, (0,1,2,3,4,5),
unde g este variabila care va reține numărul acestora:
Mai întâi, voi citi în continuare de la tastatură la fiecare pas o literă!
164
5. Priviți secțiunea de cod de mai jos:
...
g = 0
while g<6:
c = input('Litera este: ')
c = c.upper()
if c not in tara:
g = g + 1
print('Fara',c,'- mai ai',str(6-g),'incercari!')
continue
else:
#daca exista litera
Dacă litera citită nu este în cuvânt, nu are rost să efectuăm ori să testăm în
continuare nimic, ci doar să incrementăm valoarea variabilei g cu o unitate
și să afișăm un mesaj despre numărul de greșeli rămase, apoi reluăm ciclul
cu ajutorul clauzei continue.
6. Dacă există litera, avem situații în care se regăsește de mai multe ori în
șirul reținut de variabila tara, deci le vom testa pe toate cu un ciclu for,
înlocuind fiecare apariție în variabila rasp. Spre exemplu, dacă a fost
introdus caracterul "A", în șirul tara există de două ori:
A
U
S
T
R
I
A
–
–
–
–
–
–
–
–
–
A
Așadar, variabila rasp va reține ulterior
A
–
–
–
șir ce îl vom afișa corespunzător pentru utilizator la fiecare pas, indicându-i
faptul că a ghicit o literă. Bineînțeles că variabila g nu va fi incrementată în
această situație...
Să vedem secțiunea de cod:
165
...
else:
#daca exista litera
rasp_temp = list(rasp)
rasp = ""
for x in range(len(rasp_temp)):
if c == tara[x]:
rasp_temp[x] = c
rasp += rasp_temp[x]
print(rasp)
Observații importante
Șirurile de caractere nu permit modificarea unui anumit caracter
direct. Am folosit pentru rasp conversia explicită spre tipul list în
variabila temporară rasp_temp pentru a putea lucra.
Am resetat conținutul variabilei rasp ca fiind un șir gol și vom forma
unul din nou, la fiecare pas, adăugând câte un caracter din lista
rasp_temp. Înainte decidem cu un if dacă poziția curentă din
listă este chiar c, atunci o modificăm; altfel, rămâne aceeași.
La final, tipărim noul șir de afișat reținut de variabila temp.
Se va proceda apoi similar și pentru celelalte litere ghicite, secțiunea
de cod fiind în ciclul while.
Dacă rulez programul acum, deja arată decent:
7. Mai rămâne să oprim executarea atunci când cuvântul a fost descoperit
ori a fost atins numărul maxim de încercări și am terminat:
166
tari = ['AUSTRIA', 'BELGIA', 'BULGARIA',
'CIPRU', 'CEHIA', 'CROATIA', 'DANEMARCA', 'ESTONIA',
'FINLANDA', 'FRANTA', 'GERMANIA', 'GRECIA', 'UNGARIA',
'IRLANDA', 'ITALIA', 'LETONIA','LITUANIA',
'LUXEMBURG', 'MALTA', 'OLANDA', 'POLONIA','PORTUGALIA',
'ROMANIA', 'SLOVACIA', 'SLOVENIA', 'SPANIA', 'SUEDIA']
import random
tara = random.choice(tari)
rasp = '-' * len(tara)
print('SPANZURATOAREA')
print('Ghiceste tara din UE!')
print(rasp)
g = 0
while g<6:
c = input('Litera este: ')
c = c.upper() #doar litere mari, deci transformam
if c not in tara:
g = g + 1
#daca g == 6!
if g==6:
print('Ai pierdut! Tara era', tara)
break
else:
print('Fara',c,'- mai ai',str(6-g),'incercari!')
continue
else:
#daca exista litera
rasp_temp = list(rasp)
rasp = ""
for x in range(len(rasp_temp)):
if c == tara[x]:
rasp_temp[x] = c
rasp += rasp_temp[x]
print(rasp)
#verific daca cuvantul este complet
if rasp.find('-') == -1:
print('Felicitari!')
break #am iesit din while
167
Am scris anterior programul final.
Observații
La fiecare pas al ciclului while, avem 4 situații:
Cazul 1. Caracterul nu este găsit în cuvântul propus, iar variabila g a
ajuns la valoarea 6 – cuvântul nu a fost găsit și a fost anunțat
utilizatorul, apoi ieșim forțat prin break.
Cazul 2. Caracterul nu este găsit în cuvântul propus, însă mai sunt
disponibile încercări – anunțăm lipsa literei și ieșim din iterația
curentă cu ajutorul clauzei continue.
Cazul 3. Caracterul este detectat în cuvânt. Dacă în urma înlocuirilor,
a fost găsit șirul complet, se felicită utilizatorul și se iese cu break din
ciclul while.
Cazul 4. Dacă este detectat și înlocuit caracterul introdus, dar
cuvântul nu este complet, se continuă executarea lui while.
Deși un joc ușor, iată că programul în Python nu este unul deloc facil,
iar această variantă este una rudimentară.
PROIECT
Modificați programul astfel (user-friendly):
lista să conțină și capitalele țărilor din Uniunea Europeană
există și situația în care un caracter a mai fost introdus de la tastatură
– decideți dacă o considerați greșeală ori anunțați utilizatorul să
încerce din nou
se poate ca din eroare ori voit, utilizatorul să introducă un șir de
caractere în loc de unul singur – gestionați cazurile
dacă a fost găsit cuvântul, la final afișați o scurtă informație
interesantă despre orașul sau țara respectivă
(Pont. Folosiți un dicționar.)
Succes!
168
Funcții și module
8.1. Introducere
Am folosit frecvent funcțiile până acum, iar ele sunt de fapt niște
subrutine, adică subprograme care ne ajută la prelucrarea informației.
Exemplul 8.1. Funcția len primește ca parametru un obiect și întoarce
lungimea acestuia, fie că e șir de caractere, listă, tuplu, dicționar sau set!
Definiţia 8.1. Prin subprogram vom înţelege un ansamblu alcătuit din
declarări şi instrucţiuni scrise în vederea unei anumite prelucrări, ansamblu
implementat separat şi identificat printr-un nume.
Exemplul 8.2. Se consideră funcţia:
Se citesc două valori reale a şi b. Să se scrie un program ce afişează care
dintre valorile f(a) şi f(b) este cea mai mare.
Ce observăm? Că atât pentru calculul valorii funcţiei în punctul a, cât şi
pentru calculul valorii funcţiei în punctul b, aplicăm acelaşi tip de
raţionament: încadrăm valoarea respectivă (a sau b) într-unul dintre cele
trei intervale şi aplicăm formula de calcul corespunzătoare.
Cum procedăm? Prin utilizarea cunoştinţelor dobândite până în prezent,
scriem secvenţa de program care calculează valoarea funcţiei calculată
pentru x=a şi se mai scrie o dată (sau se copiază şi se adaptează) secvenţa
de program care calculează valoarea funcţiei calculată pentru x=b.
169
Oare nu se poate lucra şi altfel? Răspunsul este afirmativ. Se scrie un
subprogram care calculează valoarea funcţiei într-un punct x oarecare şi se
apelează subprogramul: o dată pentru x=a şi încă o dată pentru x=b.
Valorile calculate la cele două apeluri, se compară între ele şi se afişează
rezultatul cerut.
Putem enumera unele dintre avantajele utilizării subprogramelor:
reutilizarea codului - odată scris, un subprogram poate fi utilizat de
către mai multe programe;
elaborarea algoritmilor prin descompunerea problemei în altele mai
simple - în acest fel, rezolvăm cu mult mai uşor problema;
reducerea numărului de erori care pot apărea la scrierea programelor;
depistarea cu uşurinţă a erorilor - verificăm la început subprogramele,
apoi modul în care le-am asamblat (le-am apelat din cadrul
programului);
realizarea unor programe uşor de urmărit (lizibile).
Așa cum ați învățat deja, funcțiile pot fi grupate în module, adică în niște
fișiere separate cu extensia *.py, pe care le putem include în program
folosind directiva import (vezi cazul random din capitolul anterior).
8.2. Funcții
8.2.1. Crearea unei funcții
Pentru început, vom crea o funcție în cadrul unui program. Să pornim
așadar de la un caz simplu.
Exemplul 8.3. Se citeşte n, un număr natural. Să se scrie programul care
tipărește valoarea calculată a expresiei:
E 1
1
2
1
3
...
1
n
Analizați programul următor, care folosește de această dată o funcție
numită subp (de la subprogram), creată de noi:
170
funcția
Antetul funcției este "def subp(x):", iar corpul ei, instrucțiunea
compusă subordonată (setul de instrucțiuni indentate).
Funcția (subprogramul) se numește "subp".
Funcţia are un parametru numit x. Rolul său este important deoarece
precizează pentru ce valoare trebuie calculată expresia. Aşa cum
vom vedea, există posibilitatea să avem mai mulţi parametri.
Funcţia are variabile proprii - adică definite/declarate în interiorul ei.
În exemplu, s şi i. Aceste variabile se numesc variabile locale.
Am văzut că funcţia întoarce un anumit rezultat! Observaţi
mecanismul prin care am obţinut acest lucru. Calculăm expresia în
mod obişnuit. Rezultatul este reţinut de variabila locală s.
Prin instrucţiunea "return s", funcţia a primit ca valoare de retur
conţinutul variabilei s.
În terminologia utilizată în teoria subprogramelor - în particular, în cazul
funcţiilor - se utilizează termenii parametri formali şi parametri efectivi.
Definiţia 8.2. Parametrii care se găsesc în antetul funcţiei se numesc
parametri formali.
Atunci când scriem o funcţie nu cunoaştem valoarea propriu-zisă a
parametrilor. Funcţia trebuie să întoarcă rezultatul corect, oricare ar fi
valoarea lor. Din acest punct de vedere ei se numesc formali.
Definiţia 8.3. Parametrii care
parametri efectivi (argumente).
se utilizează la apel
se numesc
La apel, lucrurile stau altfel: valorile acestora sunt cunoscute. Prin urmare,
aceştia se numesc parametri efectivi. De exemplu, pentru apelul
"rez = subp(n)", parametrul efectiv este n.
171
Exemplul 8.4. Mai jos am definit o funcție care citește de la tastatură
numărul de componente ale unei liste, apoi elementele sale:
Am rulat programul și am introdus niște date la întâmplare:
Observații. Funcția nu are un parametru formal, însă întoarce prin return
o listă nouă care poate fi reținută de o variabilă din program. Nu am
specificat tipul de date reținut de elementele listei, așadar a fost str, cel
implicit pentru funcția input – puteți folosi conversia explicită la citire.
Exerciții. Creați câte o funcție care citește o listă cu elemente de tip int,
apoi float. De asemenea, realizați o funcție care citește un dicționar!
172
Exemplul 8.5. Continuăm definirea funcțiilor pentru listele noastre și
realizăm una care afișează o listă, element cu element:
În acest caz nu am avut nevoie de o valoare sau obiect care să fie returnat,
ci doar de afișat, deci return lipsește, fiind opțional. Variabila lista1 reține
obiectul creat de funcția creare_lista, care este trimis ca parametru efectiv
pentru funcția afisare_lista:
Exercițiu. Stilizați puțin funcția afisare_lista. Parcă ar arăta mai bine dacă
rezultatele ar fi de genul "Elementul 0: a", etc.
8.2.2. Să formăm un prim modul!
Observăm ca deja avem două funcții definite. Super! Ștergem ultimele
două rânduri de la Exemplul 8.5, care conțin apeluri către ele și salvăm pe
disc fișierul cu extensia py, să spunem operații_liste.py.
173
Eu am lucrat pe Desktop, deci vom avea acum două fișiere:
Programul
Modulul creat
iar conținutul lor este:
Observații. Am folosit directiva import pentru a include funcțiile din modul,
folosind numele său, fără extensie. Am șters funcțiile din programul meu
deoarece nu avea sens, evident. Apelul funcțiilor din cadrul modulului se
face de acum prin forma generală cunoscută: nume_modul.nume_funcție!
174
Exemplul 8.6. Pot să definesc o funcție care să afișeze deosebit numărul de
elemente ale unei liste:
Am scris funcția în modulul operatii_liste, apoi o pot apela în program:
Deja putem lucra ordonat, curat și eficient!
Notă. Eu am folosit numele modulului ("operatii_liste") pentru o mai bună
înțelegere. În practică, putem scrie doar "op_l" sau "ol", cu un comentariu
la început în interior, pentru a ne fi mai ușor la apelul funcțiilor.
Probleme propuse
1. Creați un modul care să conțină funcții personalizate pentru un șir de
caractere – citire, tipărire, afișarea numărului de caractere, etc.
2. Creați un modul care citește și afișează într-un mod user-friendly un
dicționar sau un set.
175
8.2.3. Mai mulți parametri formali
Până acum am folosit doar unul ori ... niciunul. Să spunem că ne dorim să
realizăm o funcție care adună valorile reținute de trei variabile.
Operatorul de adunare știm că poate fi folosit pentru clasele int / float și
str (concatenează două șiruri de caractere), deci o putem generaliza:
Mai sus am citit pentru fiecare dintre cele două apeluri câte 3 date de
intrare de la tastatură reținute de variabilele a, b și c. Pentru a fi efectuată
corect adunarea, am forțat după citire, prin conversie explicită, tipul de
date reținut de variabile. Pe acestea le-am trimis ca parametri efectivi
funcției noastre numită ad3, care a efectuat operația, apoi rezultatul a fost
afișat cu ajutorul lui print.
Totuși... am spus generalizare. Nu ar fi fain ca funcția să decidă cum?
176
Funcția input întoarce întotdeauna datele citite ca un șir de caractere, știm
acest aspect. De asemenea, cunoaștem deja instrucțiunea alternativă if.
Așadar, modificăm funcția creată anterior:
Am adăugat un parametru formal suplimentar (tip) pentru a putea
impune modul în care dorim să efectuăm operația de adunare.
... Clar că puteam include și tipul de date list, de exemplu. Exercițiu!
Am folosit apoi instrucțiunea if pentru a decide modul de conversie
explicită pentru fiecare dintre cele 3 valori.
De ce nu putem scrie int(x+y+z) pentru cazul întreg?
Obs. Tipul celor trei variabile care rețin datele citite trebuie să fie identic,
în acest caz. Dacă x e de tip str, iar y și z, de tip int... vom obține eroare.
Parametri și argumente
Spunem că variabilele x, y, z, tip sunt parametri, iar a, b, c, 'str' sunt
argumentele cu care apelăm funcția.
177
8.2.4. Valori implicite pentru parametri
Dacă apelam funcțiile anterioare care conțineau parametri formali, fără
unul dintre aceștia, am fi obținut cu siguranță o eroare. Revenind
la exemplul anterior, mai jos am uitat să introduc argumentul pentru tip:
print(ad3(a,b,c))
Traceback (most recent call last):
File "C:\Users\Vlad\Desktop\exemple_functii.py", line 11,
<module>
print(ad3(a,b,c))
TypeError: ad3() missing 1 required positional argument: 'tip'
in
Putem impune valori implicite pentru anumiți parametri direct în antetul
funcției, ca mai jos:
După cum observați, la primul apel, ultimul argument lipsește, însă
programul funcționează, valoarea implicită fiind 'str':
Obs. Toți parametrii pot avea valori implicite (de exemplu, 0 și 'str'), deci
putem apela funcția chiar fără niciun argument:
178
Evident, șirul rezultat va fi format din concatenarea celor 3 caractere "0":
De ce sunt caractere? ... pentru că cele 3 valori implicite au fost convertite
explicit pe ramura if către tipul str.
8.2.5. Funcții anonime - lambda
În cadrul codului nostru, putem avea nevoie câteodată de anumite mici
funcții fără nume, cu unul sau mai mulți parametri, iar corpul să conțină o
unică expresie – ceva rapid și ușor! Forma generală este
lambda parametri : expresie
Expresia este evaluată pe baza argumentelor, iar valoarea rezultată,
întoarsă spre program.
Exemplul 8.7. Să spunem că dorim o funcție care primește ca argumente
două numere și întoarce media aritmetică a valorilor acestora:
Super fain!
179
8.2.6. Probleme rezolvate
Problema 1. Revenim la exemplul de funcţie dat în paragraful 8.1.
Așadar, se consideră funcţia:
Se citesc două valori reale a şi b distincte. Să se scrie un program care
afişează care dintre valorile f(a) şi f(b) este cea mai mare.
Rezolvare. Programul este afișat mai jos:
Problema 2. Se citesc două numere întregi m şi n. Se cere să se tipărească
cel mai mare divizor comun şi cel mai mic multiplu comun al lor.
Rezolvare. Cunoaşteţi deja modul în care se calculează cel mai mare divizor
comun pentru două numere naturale date. Cel mai mic multiplu comun a
două numere se poate determina împărţind produsul lor la cel mai mare
divizor comun al lor.
Prin urmare, scriem o funcţie cmmdc cu doi parametri formali m şi n, care
întoarce o valoare întreagă - cel mai mare divizor comun al lor.
180
Problema 3. Triunghi special. Se citesc două numere naturale m şi n mai
mici decât 10. Se cere ca programul să afişeze un triunghi, după regulile pe
care le deduceţi din exemplele următoare:
Rezolvare. Se observă că dacă n=5 trebuie să obţinem şirul 5, 6, 7, 8, 9,
1, 2, 3, ... Problema este de a putea număra începând de la n, iar când s-a
depăşit valoarea 9, de a relua numărarea de la 1. Vom utiliza o funcţie
(succesor) care primeşte ca parametru de intrare un număr k şi returnează
valoarea următoare, în logica prezentată mai sus.
Alt aspect al problemei este realizarea tipăririi acestor valori pe m linii, linia
1 având o singură valoare, linia a doua două valori, etc. Algoritmul este
implementat în procedura tipar, care are ca parametri formali pe m şi n.
Valorile lor sunt citite în programul principal:
181
Vom rula pentru valorile ca exemple:
182
Problema 4. Se citesc două numere naturale m<n. Se cere să se tipărească
toate numerele palindrom aflate între m şi n. Un număr este palindrom
dacă, citit de la stânga la dreapta şi citit de la dreapta către stânga,
rezultatul este acelaşi. De exemplu, numărul 121 este palindrom.
Rezolvare. Să analizăm problema. Este necesar să fie testate toate numerele
între m şi n, pentru ca apoi să fie tipărite numai cele care îndeplinesc
condiţia cerută.
Pentru fiecare număr, avem subproblema verificării proprietăţii de număr
palindromic. Pentru aceasta, vom scrie o funcţie numită palindrom care
are rolul de a testa dacă un număr este sau nu palindrom. Analiza
proprietăţii de număr palindromic o efectuăm construind răsturnatul
(inversul) acelui număr şi verificăm dacă cele două valori (numărul şi
răsturnatul său) sunt egale.
Construirea ”inversului“ (nu în sens matematic) unui număr natural este şi
ea o subproblemă a problemei verificării proprietăţii de palindrom.
Vom scrie o funcţie invers, care va returna inversul unui număr natural
transmis ca parametru.
Urmărind apelurile, vom constata că programul principal apelează funcţia
palindrom, iar funcţia palindrom apelează la rândul ei funcţia invers.
Programul apelant al funcţiei palindrom este programul principal, în timp
ce programul apelant al funcţiei invers este subprogramul palindrom.
Care este avantajul scrierii fiecărei funcţii?
Acesta este dat de faptul că, atunci când scriem funcţia, ne concentrăm
exclusiv asupra ei, deci posibilitatea de a greşi este mai mică. Dacă
dispunem de funcţie, algoritmul în continuare devine mult mai simplu. În
plus, este posibil ca oricare dintre funcţii să poată fi folosită şi în alte cazuri,
la rezolvarea altor probleme.
Ordinea definirii celor două subprograme nu este importantă... în C++
funcţia invers, de care are nevoie funcţia palindrom, trebuia declarată
anterior acesteia (vezi programul pe pagina următoare).
Exercițiu. Un număr natural este superpalindrom dacă este palindrom atât
el cât şi pătratul său. Scrieţi, pe baza programului dat, un program
care listează toate numerele cu această proprietate aflate între doi întregi
a şi b (a<b<30000).
183
Testați și voi programul pentru diverse valori:
184
8.2.7. Probleme propuse
1. Scrieţi o funcţie care primeşte ca parametru lungimea laturii unui pătrat
şi returnează aria sa.
2. Scrieţi un subprogram care primeşte ca parametru lungimea laturii unui
pătrat şi returnează atât lungimea diagonalei, cât şi perimetrul pătratului.
3. Scrieţi o funcţie care primeşte ca parametri de intrare lungimile celor
două catete ale unui triunghi dreptunghic şi returnează lungimea
ipotenuzei.
4. Scrieţi o funcţie care primeşte 3 parametri de tip real, cu semnificaţia de
lungimi pentru 3 segmente. Funcţia va returna 1 dacă cele trei segmente
pot forma un triunghi şi 0, în caz contrar.
5. Scrieţi o funcţie care returnează prima cifră a unui număr natural.
De exemplu, dacă parametrul efectiv este 127, funcţia va returna 1.
6. Să se tipărească toate numerele prime aflate între doi întregi citiţi.
Programul va folosi o funcţie care testează dacă un număr este prim
sau nu.
7. Scrieţi un program care tipăreşte numerele întregi găsite între două
valori citite, numere care se divid cu suma cifrelor lor. Programul va utiliza
o funcţie care returnează suma cifrelor unui număr întreg primit ca
parametru.
8. Design triunghiular. Triunghiul de mai jos este generat de un algoritm.
Descoperiţi acest algoritm şi folosiţi-l pentru a scrie un program care
citeşte numărul n de linii şi generează triunghiul cu n linii corespunzător.
1
232
34543
4567654
567898765
67890109876
7890123210987
9. Scrieți un subprogram care să realizeze reuniunea, intersecția sau
diferența a două mulțimi, în funcție de un parametru impus la apel.
185
8.3. Vizibilitatea variabilelor
8.3.1. Variabile locale și globale
Exemplul 8.8. Priviți programul următor:
Am creat o variabilă x și i-am atribuit valoarea întreagă 6. Am definit apoi o
funcție, numită inc, în speranța că x va fi incrementat cu o unitate, însă
rezultatul este surprinzător!
Cu ce am greșit? Am totuși o vagă bănuială... anterior am prezentat faptul
că funcțiile au variabile proprii, care se numesc variabile locale, ce nu pot fi
accesate din exterior. Am prezentat funcția build-in numită id(), care oferă
identitatea unică a obiectelor reținute în memorie.
Să o folosim acum:
Ce observăm? Parametrul, respectiv variabila x din corpul funcției, este un
obiect complet diferit de celălalt x din program după atribuire, deci nu este
recunoscută în afara funcției!
Cum putem rezolva totuși problema? Câteodată trebuie să modificăm
conținutul variabilelor din exteriorul corpului funcțiilor noastre...
186
Trebuie să anunțăm funcția despre faptul că variabila noastră x este cea din
exterior și vom utiliza cuvântul cheie global, precum mai jos:
Nu a mai fost necesar niciun parametru ori argument la apel în acest
caz. Dacă ar fi existat, ar fi apărut o eroare ... x nu putea fi și variabilă
locală și globală în același timp în interiorul funcției inc:
O variabilă definită în exteriorul funcției este globală implicit –
trebuie doar să specificăm acest fapt în interior.
Variabilele declarate în interiorul funcțiilor sunt numite variabile
locale - mai precis, pot fi declarate în orice bloc (instrucțiune
compusă) din cadrul acestora.
Trebuie să folosim cuvântul cheie global pentru a scrie și a citi o
variabilă din afară în interiorul unei funcții.
Folosirea lui global în afara funcțiilor nu are niciun efect.
187
Exemplul 8.9. Vom crea o funcție care adună o valoare trimisă ca argument
unei variabile definită în program:
Variabila x este globală, iar variabila a este locală (parametrul). Funcția
primește ca argument valoarea 8 reținută apoi de a și folosită la operația
de adunare cu x.
Obs. Dacă nu am fi specificat vizibilitatea lui x prin declarația "global x",
atunci am fi obținut iar o eroare... se încerca operația de atribuire prin
adunare pentru o variabilă locală ce nu avea un conținut inițial:
UnboundLocalError: local variable 'x' referenced before
assignment
Funcția nu ar fi știut cine este x local. Testați!
Exemplul 8.10. Bineînțeles că putem avea o variabilă locală și una globală
cu același nume, însă sunt obiecte diferite, în funcție de locație:
Atenție însă la vizibilitatea valorilor!
188
8.3.2. Variabile nelocale
În programele voastre cu siguranță veți folosi funcții care se vor regăsi în
interiorul altor funcții – acestea se numesc imbricate. Ce ne facem
în situația în care vom folosi variabile cu același nume în cadrul lor? Dacă
ne dorim însă ca variabilele să nu fie locale, însă nici globale?
Exemplul 8.11. Să analizăm programul următor:
Mai sus, în cadrul funcției exterior() se află subprogramul interior().
Deoarece x a fost declarat nelocal, valoarea lui x din funcția exterior() s-a
modificat, însă variabila globală din programul principal nu...
Deci, dacă modificăm variabila nelocală, are efect și asupra celei locale.
8.4. Transmiterea parametrilor
8.4.1. Introducere
Spre exemplu, în limbajul C++ există două mecanisme de transmitere a
parametrilor: prin valoare şi prin referinţă.
Transmiterea prin valoare se utilizează atunci când suntem interesaţi ca
subprogramul să lucreze cu acea valoare, dar în prelucrare, nu ne
interesează ca parametrul efectiv (cel din blocul apelant) să reţină valoarea
modificată în subprogram.
189
Parametrii sunt transmişi prin referinţă atunci când ne interesează ca la
revenirea din subprogram, variabila transmisă să reţină valoarea stabilită în
timpul executării subprogramului.
Limbajul Python este deosebit și totodată asemănător cu Java, în acest caz.
Să vedem în continuare mecanismul!
8.4.2. Mai mult despre variabile (mutabile / imutabile)
Am tot precizat faptul că aproape orice dată în Python este un obiect, iar că
limbajul este puternic orientat pe obiecte. Variabila nu este obiectul, ci ea
face referire la acel obiect! Priviți un exemplu deja clasic:
Este surprinzător! Deși credeam că am copiat lista1 într-un nou obiect
numit lista2, de fapt... am obținut un nume nou (o referință) către ea.
Modificând lista2, am alterat implicit și lista1, deoarece ele sunt referințe
către același obiect – o instanțiere a clasei list.
Așadar, un nume și un obiect sunt lucruri total diferite!
Folosim funcția id() pentru a verifica identitatea unică a obiectelor reținute
de cele două variabile:
Cele două referințe / variabile, adică lista1 și lista2, indică același obiect!
190
Un astfel de tip se numește mutabil (în engleză, mutable) deoarece poate
fi modificat pe parcursul programului, după instanțierea clasei.
Listele, seturile și dicționarele sunt mutabile!
Să luăm un exemplu acum pentru numere întregi cu semn, deci instanțieri
ale clasei int:
Ce observăm de această dată? La prima afișare, ambele variabile, x și y,
indicau același obiect, respectiv valoarea întreagă 6:
În momentul în care am folosit atribuirea unei noi valori pentru y,
(y = y + 1), s-a terminat legătura cu variabila x!
Un obiect nou a fost creat în memorie, cu ID-ul unic 262457360, către care
variabila y indică acum:
191
Deci, acest tip de obiecte nu poate fi modificat și îl numim imutabil
(în engleză, immutable).
Tipurile int, float, str și tuple sunt imutabile!
Am lămurit acest aspect complex în două-trei pagini!
8.4.3. Stai! Cum copiez de fapt două obiecte mutabile?
Bună întrebare! La pagina 190 am copiat referința spre obiectul de tip listă,
prin operația de atribuire lista2 = lista1 și nu conținutul acesteia, dat fiind
faptul că tipul era mutabil.
Cum procedăm? Păi... mă gândesc că aș putea crea o listă vidă, apoi să
folosesc instrucțiunea for și să copiez element cu element... complicat!
Avem la dispoziție funcții specializate care se găsesc în modulul copy:
Cele două funcții sunt distincte: una superficială (copy) și alta în profunzime
(deepcopy) – în engleză, shallow or deep copy.
Observați mai sus că ultimul obiect din lista1 este tot o listă (mutabilă).
Folosind copy, lista2 reține noi referințe spre elementele imutabile 1, 2, 3,
precum și o referință spre aceeași listă din list1, adică [4,5].
Pe de altă parte, deepcopy crează o copie cu obiecte noi în profunzime
(recursiv), a.î. toate elementele sunt noi, deci referite diferit în memorie.
192
Să analizăm exemplul de mai jos:
Deoarece elementul lista1[0] conține un obiect imutabil, de tip int, după
ambele tipuri de copiere, prin modificarea valorilor în noile liste observăm
că am obținut elemente noi, cu valori diferite, iar lista1 a rămas intactă.
Dacă încercăm să modificăm în profunzime valorile, precum elementul cu
indice 0 din lista [4,5]?
Priviți diferența dintre copierea superficială și cea în profunzime!
Obiectul lista2 reține doar referința spre lista [4,5], deci atunci când am
modificat valoarea elementului [3][0], adică valoarea 4 din lista imbricată,
s-a modificat și în lista1 – superficial!
Obiectul lista3 conține referințe spre obiecte total noi, cu id-uri diferite
pentru cele mutabile, în profunzime, deci valoarea 9 a fost impusă doar
pentru ea, lista1 rămânând astfel neschimbată.
Atenție la tipurile de date mutabile și imutabile!
Variabilele rețin referințe spre obiecte - aspect esențial în Python!
193
8.4.4. Revenim la transmiterea parametrilor
Limbajul Python este deosebit, iar parametrii sunt transmiși ca referințe
de obiecte prin valoare.
Exemplul 8.12. Am apelat o funcție și în cadrul ei, inițial x reține referința
spre obiectul trimis ca argument (a și x au același id), însă la incrementare,
se creează un obiect nou, x local, la care se adună 1 – obiectul referit de a
rămâne nemodificat în program și funcție:
Reținem că tipurile de date imutabile sunt trimise prin valoare – nu se pot
modifica în subprogram!
Exemplul 8.13. Luăm cazul unei liste acum formată din 5 elemente (obiectul
este mutabil). De fapt ce este o listă? Un obiect format din alte obiecte,
în acest caz imutabile (tipul int):
194
Să analizăm următorul program:
Observăm că de această dată, argumentul fiind mutabil, referințele spre
obiect reținute de lista1 și lst nu a fost modificate, însă conținutul listei a
putut fi alterat și apoi vizibil în programul principal!
Atenție însă! Referința spre obiectul lista1 este trimisă de asemenea prin
valoare ca argument, așadar putem modifica conținutul obiectului mutabil,
însă pe ea nu, cum ar fi de exemplu folosirea unei atribuiri în subprogram:
Prin atribuire, variabila lst reține o referință spre un obiect local nou.
Reținem că tipurile de date mutabile sunt transmise și ele prin valoare
– deci nu se pot modifica în subprogram! Cu toate acestea, componentele
lor, obiecte la rândul acestora, pot fi alterate.
Nu uitați!
int, float, str și tuple sunt imutabile!
list, set și dict sunt mutabile!
195
8.5. Poziția și ordinea scrierii funcțiilor
8.5.1. Ce înseamnă de fapt un limbaj interpretat?
Limbajul Python este interpretat, deci atunci când executăm un program,
acesta preia secvențial comandă după comandă și încearcă rularea lor.
Exemplul 8.14. Considerăm un program banal și încercăm să îl executăm,
deși știm că vom obține cu siguranță o eroare:
Surprinzător este rezultatul:
Atribuirea a fost efectuată și valoarea variabilei a este totuși tipărită!
Să vedem cum a judecat Python:
pe prima linie a detectat cuvântul cheie def, deci urmează o definiție
pentru o anumită funcție pe care o reține în memorie (ea este ok
semantic și sintactic, deși nu va face nimic – x e local);
creează o variabilă numită a care reține o referință spre obiectul
imutabil de tip str;
tipărește valoarea reținută de variabila a;
apelează funcția test cu argumentul a, iar eroarea este afișată
deoarece un șir de caractere nu poate fi concatenat cu un întreg.
196
Obs. În cazul unui limbaj care necesită compilarea programului, evident că
nu se va mai afișa nimic, ci doar anunțată eroarea imediat.
8.5.2. Unde putem defini o funcție?
Exemplul 8.15. Nu putem apela o funcție care încă nu a fost definită:
Variabila a primit valoarea 23, apoi a fost apelată o funcție inexistentă.
Așadar, creăm funcția înainte și apoi o putem apela în program.
8.5.3. Mai multe funcții
Exemplul 8.16. Să presupunem că avem două funcții, numite unu și doi, ca
în programul de mai jos (una o apelează pe cealaltă):
Ce observăm? Funcțiile nu sunt executate, ci doar reținute, deci ordinea
acestora nu contează, atât timp cât sunt definite înaintea apelului!
197
Cum putem greși? Atunci când programele noastre devin destul de mari,
ordinea definirii subprogramelor este importantă, deoarece putem din
greșeală să le poziționăm astfel:
A fost reținută definiția funcției unu, apoi variabilei a i s-a atribuit valoarea
10. Se apelează funcția unu, însă până în acel moment, definiția funcției doi
este inexistentă, deci rezultă o eroare la interpretare:
8.5.4. Concluzii
Atenție la detalii în orice demers, fie că este un program în Python, un nou
modul sau pur și simplu un proiect în grădină ori de bricolaj. :)
Și în programare lucrurile sunt foarte fine. Cine spune că Python este ușor,
se înșeală amarnic, precum observați. Multe aspecte trebuie luate în
considerare, noțiunile teoretice trebuie stăpânite solid, iar o imaginație
bogată, împreună cu o disciplină de fier vor face diferența și vă vor oferi cu
siguranță satisfacții în lumea coding-ului.
Veți ajunge să știți la perfecție cum funcționează poate un cod format din
mii de linii – creația voastră! Nu uitați de comentarii... cândva vor conta!
198
8.6. Universul modulelor
8.6.1. Python Standard Library
Am folosit deja modulele random și copy pentru a putea genera numere
aleatoare ori pentru a copia date mutabile. Acestea fac parte din biblioteca
standard a limbajului Python, numită în engleză Python Standard Library,
care conține o multitudine de alte module utile:
https://docs.python.org/3/library/
Nu avem cum să le analizăm pe toate aici, ci trebuie doar să știm de
existența acestora și în caz de nevoie, să ne documentăm corespunzător,
apoi să folosim subrutinele unui anume modul care ne pot fi de folos!
Pentru a include un modul în programul nostru, am văzut că folosim
directiva import, urmată de numele bibliotecii:
import random
Putem include mai multe module într-o singură comandă:
import random, copy
sau doar o parte dintre subrutinele conținute de un modul:
from copy import copy,deepcopy
deoarece dorim să fim eficienți – includem doar ce ne este necesar.
Limbajul Python este extensibil prin noi module pe care utilizatorii din
toată lumea le pot crea și eventual distribui. La paragraful 8.2.2. am creat
un prim modul care conținea două funcții definite de noi. Acesta a fost
salvat pe hard-disk sub forma unui fișier text cu extensia py. De fiecare
dată când avem nevoie să apelăm o anumită funcție din acel modul, îl
importăm, apoi folosim sintaxa:
nume_modul.nume_functie(argumente)
Un modul poate conține funcții, variabile, clase și chiar cod executabil, însă
într-un program el poate fi inclus o singură dată prin directiva import.
199
8.6.2. Modulul math - fiți autodidacți!
Exemplul 8.17. Să presupunem că avem de calculat expresia:
G(x) = sin(x) + cos(x) + cos(2*x)
pentru x, o valoare citită de la tastatură.
Încerc mai întâi în consolă o formulă simplă:
dar observ imediat faptul că funcția cosinus nu este oferită implicit de către
interpretorul Python. Deschid pagina web a bibliotecii standard și observ că
există modulul math:
https://docs.python.org/3/library/math.html
Minunat! Găsesc acolo pe lângă cos, o mulțime de alte funcții matematice
utile și studiez puțin despre acestea (sunt cu zecile, poate voi avea nevoie
mai târziu de una dintre ele).
Revin la programul meu și mai întâi import modulul, iar apoi scriu restul de
cod care rezolvă problema:
200
I/O. Fișiere text
9.1. Introducere
9.1.1. Modelul black-box
Un program cuantifică un algoritm de calcul și are rolul de a prelua anumite
date de intrare (precum niște stimuli) pe care le prelucrează și le oferă spre
ieșire (un răspuns):
date de ieșire
date de intrare
stimuli
PROGRAM
răspuns
Acesta se numește modelul black-box, care abstractizează primar orice
element "viu" din jurul nostru. Motorul mașinii are o turație mai mare dacă
este apăsată mai tare pedala de accelerație; dacă ne este frig, mușchiul
firului de păr se contractă și ni se face "pielea de găină"; dacă apăsăm pe
telefon o anumită pictogramă, se deschide apoi programul asociat, ș.a.m.d.
De altfel, modelul este prezent în prima pagină la cursul Teoriei Reglării
Automate de la Facultatea de Automatică, UPB București. :)
Până în prezent am folosit funcțiile input și print pentru a citi și scrie date
în consola interactivă Python deoarece este un mod facil de a verifica și
executa programele.
9.1.2. Fișiere text
În practică, lucrurile sunt mai complexe. De regulă, când scriem un
program, îl testăm cu câteva date introduse de la tastatură. Astfel de teste
nu sunt semnificative. S-ar putea ca programul să aibă bug-uri (termen
folosit de programatori, se referă la erorile ascunse pe care le-ar putea
avea un program). Apoi, nu vedem cât de eficient este programul nostru,
deși anumite calcule de eficiență se pot face înainte de a îl scrie.
201
Din acest motiv datele de test se pot genera aleator, în număr mare și
reținute în fișiere separate de tip text. Programul nostru va citi datele de
intrare din fișiere text, iar datele de ieșire vor fi scrise tot în fișiere text:
Fișierele sunt de tip text și se pot crea cu ajutorul programului Notepad ori
direct din editorul consolei interactive Python. Pentru a fi identificate mai
ușor, putem schimba ca mai sus extensia lor – *.in pentru datele de intrare,
iar *.out, pentru cele de ieșire (o formă standardizată).
Atenție! La toate concursurile de informatică programele concurenților
sunt testate cu ajutorul fișierelor text.
9.2. Deschiderea și închiderea fișierelor text
9.2.1. Un prim exemplu de citire
Am creat fișierul date.in pe Desktop și am scris în interiorul său niște date
pe două linii:
Într-un program numit fisiere_text.py, tot în același director - pe Desktop,
scriu următoarele două comenzi:
202
Execut programul, iar în consolă este afișat conținutul fișierului text:
Am citit primul fișier text!
Variabila f reține o referință spre un obiect ce aparține clasei file,
care este creat de funcția open și are menirea de a permite citirea și
modificarea fișierului în funcție de necesitate.
În documentație, variabila f se mai numește și handler.
În exemplu, funcția open deschide fișierul indicat ca prim argument
spre citire, deoarece al doilea parametru este "r" (de la read).
Metoda / funcția read() citește întreg fișierul care este afișat apoi de
print în consolă.
Observați faptul că în fișierul date.in există o ultimă linie fără
conținut care a fost afișată în consolă prin program.
9.2.2. Întotdeauna închidem fișierul deschis...
Când intrăm în casă, folosim cheia pentru a deschide ușa, apoi o securizăm
imediat – nu se știe niciodată ce se poate întâmpla dacă o lăsăm deschisă!
Așa și pentru fișierul text .... L-am deschis, am citit, apoi l-am închis folosind
funcția/metoda fără argument close() – simplu și eficient:
Precum limbajul Java, Python are un sistem (numit Garbage Collector)
bine pus la punct prin care elementele nefolositoare sunt automat șterse
din memorie, însă e mai sigur să o facem noi înainte...
203
Sunt situații în care la interpretare apare o eroare, iar funcția close nu a
mai ajuns să fie apelată, deci fișierul rămâne deschis. Un mod automat de
închidere/deschidere a fișierelor text este folosirea cuvântului cheie with:
Citim astfel: "cu fișierul numit date.in deschis pentru citire și reținut de f,
executăm următorul bloc de instrucțiuni". La final, oricum ar fi, fișierul text
este închis corespunzător.
9.2.3. Funcția open
În exemplul din cadrul paragrafului anterior am folosit funcția built-in open
pentru a citi un fișier text. Să vedem forma sa simplificată acum:
open(nume_fișier, mod_deschidere)
unde parametrul mod_deschidere poate lua următoarele valori:
r
w
a
x
+
– deschis pentru citire (implicit)
– deschis pentru scriere (dacă există, fișierul este golit / rescris)
– deschis pentru adăugare (append)
– deschis doar pentru creare (dacă fișierul există, obținem eroare)
– deschis pentru scriere și citire
Vom lucra în acest capitol folosind două fișiere de text, unul pentru datele
de intrare și altul pentru datele de ieșire, pe care le deschidem ca mai jos:
with open("date.in","r") as f:
#citim fisierul
...
with open("date.out","w") as g: #sau "a" pentru adăugare
#scriem in fisier
Atenție! Cele două fișiere text se găsesc în același director cu cel ce conține
programul *.py. Altfel, trebuie trecută calea completă...
204
9.3. Citirea fișierelor text
Exemplu de referință. Am scris alfabetul pe patru linii:
Fișierele text conțin o înșiruire de caractere, de cele mai multe ori pe mai
multe linii. Atunci când deschidem un fișier, poziția de citire (îi vom spune
pointer) se găsește pe primul caracter cu indice 0.
Observați faptul că atunci când salvați pe disc fișierul text, dacă nu ați lăsat
un rând liber la final, este introdus automat de IDLE. Se forțează astfel
închiderea ultimei linii, fiind un standard de programare de zeci de ani.
Dacă ați introdus-o, bineînțeles că nu va mai fi adăugată una suplimentară.
Să vedem cum putem citi datele din acest fișier.
9.3.1. Metoda read()
Metoda read, apelată fără parametru, citește toate caracterele până la
finalul fișierului text și le întoarce sub forma unui șir de caractere:
Variabila citit reține șirul de caractere întors de funcția read, iar acestea
sunt afișate apoi folosind print. Nu prea ne ajută însă o simplă citire
deoarece în acest caz poate dorim să eliminăm caracterele care rețin
sfârșitul de linie.
205
Între două linii și la finalul fișierului există caracterul newline, invizibil,
ce indică sfârșitul de linie și poate fi detectat prin "\n" (pentru Apple, "\r"),
respectiv înlocuit cu spațiu, precum mai jos, folosind metoda replace:
Am citit fișierul text și am preluat toate datele reținute sub forma unui șir
de caractere, fiecare delimitate de un singur spațiu.
Poziția pointer-ului. După apelul metodei read, cursorul se va găsi la
sfârșitul fișierului de date. Dacă încercăm să recitim conținutul, printr-un
nou apel, va fi afișată o linie vidă. Pentru a afla poziția curentă, folosim
metoda tell a obiectului f:
print( f.tell() )
ceea ce va afișa 54 în cazul nostru.
Pentru a muta pointerul într-o anumită poziție din fișier pentru o citire,
folosim metoda seek(pozitie_de_inceput):
with open("date.in",'r') as f:
f.seek(14) #am mutat pointerul pe pozitia 14
citit = f.read() #citesc acum de acolo
print(citit)
Programul de mai sus afișează datele începând cu litera "h". Testați!
206
De asemenea, putem citi doar primele k caractere începând cu poziția
curentă, folosind o valoare ca argument pentru funcția read:
Mai sus am poziționat cursorul pe linia a doua și am afișat primele 13
caractere, adică pe toată:
Atenție. De ce am pornit de la 15? newline deși invizibil, este și el prezent
în obiectul f și în fișier. Ca să pornesc de la litera "h", am considerat așa:
prima linie = 13 (7 litere, 6 spații) + 2 (newline, "\n") = 15
Primul caracter din fișier are poziția 0, deci seek(15) se oprește la al 16-lea
caracter, adică fix la litera "h". Pe cale de consecință, a doua linie începe
de la 30!, iar a treia, de la 45, ...
9.3.2. Conversia explicită spre o listă. Metoda readlines()
Pentru a întelege mai bine cum este reținut și citit fișierul text, putem
efectua o conversie explicită a obiectului f spre tipul list, obținând liniile în
elemente de tip str separate, lucrul fiind astfel mult mai ușor:
Se va afișa:
['a b c d e f g\n', 'h i j k l m n\n', 'o p q r s t u\n',
'v x y z\n']
Fiecare element al listei conține și indicatorul de linie nouă "\n", pe care va
trebui să îl eliminăm similar folosind funcția replace (vezi pagina 206):
207
Rezultatul este acum unul decent – avem acces la linii printr-o listă:
Alternativă. Există metoda readlines care este identică procedeului
anterior. În loc de lista_linii = list(f), scriem lista_linii = f.readlines().
9.3.3. Metoda readline()
Există situații când fișierul text nu are același număr de caractere pe fiecare
linie, ori poate dorim să citim câte o linie din fișier succesiv, așa că putem
folosi funcția readline(), care preia linie cu linie datele:
Variabila linia_curenta reține un șir de caractere pe care știți să il
manipulați deja. Citim o linie, o prelucrăm, apoi următoarea, ș.a.m.d.
208
9.4. Scrierea fișierelor text
Pentru a scrie într-un fișier text, trebuie să îl deschidem corespunzător în
acest sens prin open, folosind parametrii "w" (rescriere) sau "a"
(adăugare). În ambele cazuri, dacă fișierul nu este existent pe disc, va fi
creat automat unul nou, cu conținut vid.
Exemplul 9.3.1. Vom genera aleator 10 de numere din intervalul [1,100] pe
care le vom scrie în fișierul text "date.out", pe o linie:
Deschidem fișierul text și citim rezultatul:
Am deschis fișierul text cu parametrul "w", deci la fiecare executare a
programului acesta va fi rescris.
Instrucțiunea repetitivă for am folosit-o pentru a scrie de zece ori o
pereche de date – numărul aleator și spațiul următor.
Putem modifica programul pentru a scrie 100 de numere aleatoare, câte 10
pe fiecare linie, spre exemplu:
209
Deschid iar fișierul pentru a vizualiza rezultatele:
Exercițiu. Încercați să realizați un program care citește toate valorile
reținute de fișierul "date.out" și afișează în consolă suma lor.
Exemplul 9.3.2. Modific programul anterior astfel încât să scriu în fișier câte
o linie la fiecare iterație – acum voi folosi parametrul "a", pentru adăugare.
Fișierul trebuie să fie gol ori inexistent, altfel voi adăuga încă 10 linii la cel
pe care îl am acum salvat pe disc, evident. La început scriem
open('date.out','w').close()
ce forțează o rescriere vidă a fișierului, apoi se închide imediat.
Programul este cel de mai jos:
Obs. Dacă fișierul "date.out" nu există, va fi creat automat unul cu un
conținut gol. linie_curenta reține linia pe care o scriu de 10 ori.
210
Exemplul 9.3.3. Se citesc n linii de la tastatură. Să se creeze un program
care să le rețină într-un fișier text.
Rezolvare. Analizați programul:
Pentru n=3 și un text introdus, în consolă a funcționat astfel:
Am verificat și fișierul care conține cele 3 linii, bineînțeles. Altfel nu puteam
să îl deschidem spre citire la final...
Aplicație. Citiți datele din fișierul text "date.out" și scrieți în "date2.out"
textul care să aibă toate literele cu majuscule!
211
9.5. Cum ștergem un fișier?
Folosind modulul os (din engleză, operating system), avem acces la
anumite funcții specifice de manipulare a fișierelor.
Exemplul 9.4.1. Folosind funcția remove(nume_fișier), vom șterge fișierul
cu numele respectiv de pe disc:
import os
os.remove("date.out")
Testați. Fișierul a fost șters imediat!
Astfel, în loc să deschidem fișierul spre scriere și apoi să îl închidem imediat
(să îl golim prin open('date.out','w').close()), putem să folosim
această metodă ce ne asigură că datele anterioare reținute de fișier au fost
eliminate definitiv, cu el cu tot! Depinde cum doriți să procedați...
Putem verifica existența unui fișier cu ajutorul metodei exists(), apoi
acționăm în funcție de caz:
import os
if os.path.exists("date.out"):
remove("date.out")
else:
print('Fisierul nu este existent...')
212
Diferențe dintre versiunile 2 și 3
Vă recomand să studiați Python, versiunea 3, deoarece este modernă, mai
bună și mai ușor de învățat. În anul 2000 a fost lansată versiunea 2.0, iar
ultima, 2.7, în anul 2010, fiind un limbaj de programare extrem de popular.
Multe companii au trecut de la versiunea 2 la 3 (lansată în anul 2008)
datorită faptului că, în esență, Python 3 este cel actual – nimeni nu își
dorește să învețe ori să utilizeze un limbaj ce apune ușor...
Deoarece versiunea 3 este viitorul, bibliotecile dezvoltate de cei din
comunitate sunt bineînțeles axate spre aceasta. Similar, multe
biblioteci create pentru versiunea 2 nu sunt compatibile cu a 3-a, ori
dificil de portat.
Dacă în Python 2 șirurile de caractere erau reprezentate implicit în
cod ASCII, versiunea 3 oferă automat suport Unicode.
Print – afișarea datelor. Deși doar la nivel sintactic, totuși este
o modificare semnificativă, comanda print fiind în versiunea 3 o
funcție, a.î. apelul se face prin print("Salut!"), spre deosebire de 2
unde scriam pur și simplu print "Salut!".
Python 3 este intuitiv, precum în cazul operației de împărțire, ca de
exemplu, 7/2:
Versiunea 2. 7/2 oferă rezultatul 3 (rotunjire). Pentru a obține 3.5,
trebuie să scriem 7.0/2.0.
Versiunea 3. 7/2 are ca rezultat direct 3.5. (tipul float).
Citiți recomandările oficiale accesând link-ul de mai jos:
https://wiki.python.org/moin/Python2orPython3
Odată învățată versiunea 3, veți putea să vă adaptați totuși ușor în
cazul unui proiect care a fost deja implementat în versiunea 2.
213
Tabela codurilor ASCII
Cod Caracter
000 (nul)
001 ☺ (soh)
002 ☻ (stx)
003 ♥ (etx)
004 ♦ (eot)
005 ♣ (enq)
006 ♠ (ack)
007 • (bel)
008 _ (bs)
009 □ (tab)
010 ◙ (lf)
011 ♂ (vt)
012 ♀ (np)
013 ♪ (cr)
014 ♫ (so)
015 ☼ (si)
016 ► (dle)
017 ◄ (dc1)
018 ↨ (dc2)
019 ‼ (dc3)
020 ¶ (dc4)
021 § (nak)
Cod Caracter
022 ▀ (syn)
023 ¥ (etb)
024 ↑ (can)
025 ↓ (em)
026 → (eof)
027 ← (esc)
028 ⌐ (fs)
029 ↔ (gs)
030 ▲ (rs)
031 ▼ (us)
032 (spaţiu)
033 !
034 "
035 #
036 $
037 %
038 &
039 '
040 (
041 )
042 *
043 +
Cod Caracter
044 ,
045 046 .
047 /
048 0
049 1
050 2
051 3
052 4
053 5
054 6
055 7
056 8
057 9
058 :
059 ;
060 <
061 =
062 >
063 ?
064 @
065 A
Cod Caracter
066 B
067 C
068 D
069 E
070 F
071 G
072 H
073 I
074 J
075 K
076 L
077 M
078 N
079 O
080 P
081 Q
082 R
083 S
084 T
085 U
086 V
087 W
Cod Caracter
088 X
089 Y
090 Z
091 [
092 \
093 ]
094 ^
095 _
096 `
097 a
098 b
099 c
100 d
101 e
102 f
103 g
104 h
105 i
106 j
107 k
108 l
109 m
Cod Caracter
110 n
111 o
112 p
113 q
114 r
115 s
116 t
117 u
118 v
119 w
120 x
121 y
122 z
123 {
124 |
125 }
126 ~
127
Cod Caracter
170 ¬
171 ½
172 ¼
173 ¡
174 «
175 »
176 ░
177 ▒
178 ▓
179 │
180 ┤
181 ╡
182 ╢
183 ╖
184 ╕
185 ╣
186 ║
187 ╗
188 ╝
189 ╜
190 ╛
Cod Caracter
191 ┐
197 └
193 ┴
194 ┬
195 ├
196 ─
197 ┼
198 ╞
199 ╟
200 ╚
201 ╔
202 ╩
203 ╦
204 ╠
205 ═
206 ╬
207 ╧
208 ╨
209 ╤
210 ╥
211 ╙
Cod Caracter
212 ╘
213 ╒
214 ╓
215 ╫
216 ╪
217 ┘
218 ┌
219 █
220 ▄
221 ▌
222 ▐
223 ▀
224
225 ß
226
227
228
229
230
231
232
254
Cod Caracter
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252 ⁿ
253 ²
255
Codul ASCII extins
Cod Caracter
128 Ç
129 ü
130 é
131 â
132 ä
133 à
134 å
135 ç
136 ê
137 ë
138 è
139 ï
140 î
141 ì
142 Ä
143 Å
144 É
145 æ
146 Æ
147 ô
148 ö
Cod Caracter
149 ò
150 û
151 ù
152 _
153 Ö
154 Ü
155 ¢
156 £
157 ¥
158 _
159
160 á
161 í
162 ó
163 ú
164 ñ
165 Ñ
166 ª
167 º
168 ¿
169 _
214
1.
The Python 3 Language Reference
https://docs.python.org/3/reference/
2.
The Python Standard Library
https://docs.python.org/3/library/
3.
Manual de Informatică, clasa a IX-a, profilul real-intensiv,
autor: Tudor Sorin, Editura L&S Info-Mat, București, 2012
4.
Complemente de C++, autori: Vlad Tudor, Tudor Sorin,
Editura L&S Info-Mat, București, 2006
http://ebooks.infobits.ro/acasa/25-complemente-de-cpp.html
5.
Bazele programării în Java, autori: Tudor Sorin, Vlad Tudor,
Editura L&S Info-Mat, București, 2014
http://ebooks.infobits.ro/acasa/21-bazele-programarii-in-java.html
6.
Informatică pentru gimnaziu, Culegere de probleme, (ed. a II-a),
autor: Doru Popescu Anastasiu, Editura L&S Info-Mat, 2012
7.
www.programiz.com
8.
www.tutorialspoint.com
9.
www.stackoverflow.com
Resursă fantastică pentru întrebări dificile...
10.
www.w3school.com
215
Biblioteca Digitală de Informatică „Tudor Sorin”
www.infobits.ro
Cărți în format electronic
http://ebooks.infobits.ro
Cărți în format tipărit
www.ls-infomat.ro
L&S SOFT, București, 2020
216
0
You can add this document to your study collection(s)
Sign in Available only to authorized usersYou can add this document to your saved list
Sign in Available only to authorized users(For complaints, use another form )