Python — Partea 3

Subprograme, funcții, parametri, variabile locale și globale, tupluri, mulțimi, dicționare și recursivitate.

Material conceput pentru un începător absolut, care nu a mai programat niciodată în Python, C++ sau alt limbaj.

1. Subprograme / funcții

funcții def apel reutilizare

1.1. Ce este un program?

Un program este o succesiune de instrucțiuni pe care calculatorul le execută într-o anumită ordine.

De exemplu:

a = 5
b = 7
c = a + b
print(c)

Calculatorul execută instrucțiunile în ordine:

Pasul 1: variabila a primește valoarea 5.
Pasul 2: variabila b primește valoarea 7.
Pasul 3: calculatorul calculează 5 + 7.
Pasul 4: rezultatul 12 este memorat în c.
Pasul 5: print(c) afișează 12.

1.2. De ce avem nevoie de funcții?

Imaginăm-ne că avem un program foarte mare în care trebuie să efectuăm aceeași operație de zeci de ori.

Dacă scriem de fiecare dată toate instrucțiunile, programul devine lung și greu de înțeles.

Definiție: O funcție este un grup de instrucțiuni căruia îi atribuim un nume și pe care îl putem executa ori de câte ori avem nevoie.

1.3. Prima funcție

def salut():
    print("Salut!")

Să analizăm fiecare element:

  • def — spune lui Python că definim o funcție;
  • salut — numele funcției;
  • () — locul în care pot apărea parametrii;
  • : — marchează începutul corpului funcției;
  • print("Salut!") — instrucțiunea executată de funcție.
Foarte important: definirea unei funcții nu înseamnă executarea ei. Funcția trebuie mai întâi definită și apoi apelată.

1.4. Apelarea unei funcții

def salut():
    print("Salut!")

salut()

Linia:

salut()

este un apel de funcție.

Prin acest apel îi spunem calculatorului: „Execută instrucțiunile funcției salut”.

Exemplul 1 — Funcție care afișează un mesaj
def mesaj():
    print("Buna ziua!")

mesaj()
Buna ziua!

Mai întâi funcția este definită. Apoi, prin mesaj(), ea este executată.

Exemplul 2 — Apelarea aceleiași funcții de mai multe ori
def salut():
    print("Salut!")

salut()
salut()
salut()
Salut! Salut! Salut!

Nu a trebuit să rescriem instrucțiunea print("Salut!") de trei ori. Am definit funcția o singură dată și am apelat-o de trei ori.

Exemplul 3 — Funcție care realizează un calcul
def calculeaza():
    a = 4
    b = 7
    print(a + b)

calculeaza()
11

Funcția execută cele două atribuiri, apoi calculează suma și afișează rezultatul.

1.5. Funcții cu parametri

Uneori vrem ca funcția să primească informații din exterior.

De exemplu, nu vrem o funcție care salută mereu aceeași persoană. Vrem să putem spune:

salut("Ana")
salut("Mihai")
salut("Ioana")

Pentru aceasta folosim parametri.

def salut(nume):
    print("Salut", nume)

Aici nume este parametrul funcției.

Exemplul 4 — Un parametru
def salut(nume):
    print("Salut", nume)

salut("Ana")
salut("Mihai")
Salut Ana Salut Mihai

1.6. Funcții care returnează valori

O funcție poate nu doar să afișeze ceva, ci și să producă o valoare pe care restul programului să o poată folosi.

Pentru aceasta folosim instrucțiunea return.

def suma(a, b):
    return a + b

Dacă apelăm:

x = suma(4, 7)

funcția calculează 11 și transmite această valoare înapoi. Prin urmare:

x = 11
Exemplul 5 — Funcție care returnează suma
def suma(a, b):
    return a + b

x = suma(4, 7)

print(x)
11

1.7. Diferența dintre print() și return

print() return
Afișează ceva pe ecran. Trimite o valoare înapoi din funcție.
Este destinat afișării. Este destinat transmiterii rezultatului.
Rezultatul nu poate fi folosit direct ca valoare returnată. Rezultatul poate fi memorat într-o variabilă.
Exemplul 6 — De ce return este important
def suma(a, b):
    return a + b

x = suma(4, 7)
y = x * 2

print(y)
22

Prima funcție produce 11. Valoarea este memorată în x. Apoi putem face alte calcule cu ea.

2. Parametri și argumente

parametru argument local global return

2.1. Ce este un parametru?

Definiție: Un parametru este o variabilă scrisă în definiția unei funcții, care primește o valoare atunci când funcția este apelată.
def salut(nume):
    print("Salut", nume)

În acest exemplu, nume este parametrul.

Parametrul poate fi privit ca un „loc” în care funcția va primi o valoare.

2.2. Ce este un argument?

Definiție: Argumentul este valoarea concretă transmisă funcției în momentul apelului.
salut("Ana")

Aici:

  • nume este parametrul;
  • "Ana" este argumentul.
Exemplul 1 — Un parametru și un argument
def patrat(x):
    return x * x

print(patrat(6))

x este parametrul.

6 este argumentul.

În timpul apelului:

x = 6

Funcția calculează:

6 * 6 = 36
36
Exemplul 2 — Doi parametri
def suma(a, b):
    return a + b

print(suma(10, 3))

Avem doi parametri: a și b.

Avem două argumente: 10 și 3.

Asocierea se face în ordine:

a = 10
b = 3
13
Exemplul 3 — Trei parametri
def maxim3(a, b, c):
    m = a

    if b > m:
        m = b

    if c > m:
        m = c

    return m

print(maxim3(7, 12, 9))

La apel:

a = 7
b = 12
c = 9

Funcția compară cele trei valori și returnează 12.

12

2.3. Parametrii sunt locali funcției

Un parametru există în cadrul execuției funcției în care a fost definit.

De exemplu:

def dublu(x):
    return 2 * x

print(dublu(5))

x este un parametru al funcției dublu. El este disponibil în interiorul funcției.

2.4. Variabile locale

Definiție: O variabilă locală este o variabilă creată în interiorul unei funcții și folosită în contextul acelei funcții.
Exemplul 4 — Variabile locale
def calcul():
    x = 5
    y = 7

    suma = x + y

    print(suma)

calcul()

Variabilele x, y și suma sunt create în interiorul funcției.

12
Exemplul 5 — Parametru și variabilă locală
def patrat(n):
    rezultat = n * n
    return rezultat

print(patrat(4))

n este parametrul.

rezultat este o variabilă locală.

La apel:

n = 4
rezultat = 16
16
Exemplul 6 — Două apeluri ale aceleiași funcții
def dublu(x):
    y = 2 * x
    return y

print(dublu(3))
print(dublu(10))

La primul apel:

x = 3
y = 6

La al doilea apel:

x = 10
y = 20
6 20

2.5. Variabile globale

Definiție: O variabilă globală este o variabilă definită în afara funcțiilor, care poate fi accesată din diferite zone ale programului.
Exemplul 7 — Variabilă globală
x = 10

def afisare():
    print(x)

afisare()

Variabila x este creată în afara funcției. De aceea este globală.

10
Exemplul 8 — Două funcții folosesc aceeași variabilă globală
x = 5

def f():
    print(x)

def g():
    print(x * 2)

f()
g()
5 10
Exemplul 9 — Parametru local cu același nume
x = 100

def f(x):
    print(x)

f(5)

print(x)

Există două variabile diferite:

x global = 100
x local   = 5

În interiorul funcției este folosit parametrul local.

5 100
Atenție: faptul că putem folosi variabile globale nu înseamnă că trebuie să folosim foarte multe variabile globale. În general, este mai clar ca o funcție să primească datele necesare prin parametri și să trimită rezultatul prin return.

2.6. Recomandarea practică

def suma(a, b):
    return a + b

print(suma(10, 20))
print(suma(3, 8))
print(suma(-5, 10))

Această funcție nu depinde de variabile globale. Primește datele de care are nevoie prin parametri și returnează rezultatul.

3. Domeniul variabilelor

local global vizibilitate

3.1. Ce înseamnă domeniul unei variabile?

Definiție: Domeniul unei variabile reprezintă zona programului în care variabila poate fi folosită.

O variabilă nu este neapărat disponibilă în orice loc al programului.

3.2. Variabilă locală

def test():
    x = 10
    print(x)

test()

Variabila x este creată în funcție. Ea este locală funcției.

3.3. Ce se întâmplă dacă încercăm să o folosim în exterior?

def test():
    x = 10

test()

print(x)

Aici apare o problemă deoarece x nu a fost definită în zona în care încercăm să o folosim.

O variabilă locală nu trebuie presupusă ca fiind disponibilă oriunde în program.

3.4. Cum trimitem rezultatul în exterior?

Folosim return.

def test():
    x = 10
    return x

y = test()

print(y)

Variabila locală x este folosită în funcție, iar valoarea ei este transmisă în exterior prin return.

10

3.5. De ce este recomandat acest stil?

Funcțiile devin mai ușor de înțeles dacă:

  • primesc datele necesare prin parametri;
  • folosesc variabile locale pentru calcule;
  • returnează rezultatul.
def patrat(n):
    rezultat = n * n
    return rezultat

Aceasta este o funcție simplă, clară și reutilizabilă.

4. Tupluri

tuple index despachetare

4.1. Ce este un tuplu?

Definiție: Un tuplu este o colecție ordonată de valori.

De exemplu:

persoana = ("Ana", 17, 9.50)

Tuplul conține trei elemente:

  • "Ana"
  • 17
  • 9.50

4.2. Indexarea

Elementele sunt numerotate începând de la 0.

persoana = ("Ana", 17, 9.50)

print(persoana[0])
print(persoana[1])
print(persoana[2])
Ana 17 9.5

4.3. Tuplu versus listă

Listă Tuplu
[1, 2, 3] (1, 2, 3)
Este modificabilă. Este destinată unei colecții care nu trebuie modificată.
Utilă când datele se schimbă. Util când vrem să grupăm valori fixe.
Exemplul 1 — Coordonatele unui punct
punct = (10, 20)

x = punct[0]
y = punct[1]

print(x)
print(y)
10 20
Exemplul 2 — Parcurgerea unui tuplu
culori = ("rosu", "verde", "albastru")

for culoare in culori:
    print(culoare)
rosu verde albastru
Exemplul 3 — Despachetarea unui tuplu
punct = (5, 8)

x, y = punct

print(x)
print(y)

Python face automat:

x = 5
y = 8
5 8

5. Mulțimi

set elemente distincte in reuniune intersecție

5.1. Ce este o mulțime?

Definiție: O mulțime este o colecție de elemente în care fiecare valoare apare o singură dată.
s = {2, 4, 2, 7, 4}

print(s)

Valorile repetate sunt eliminate conceptual.

Mulțimea reprezintă valorile distincte:

{2, 4, 7}

5.2. Verificarea apartenenței

s = {2, 4, 7}

print(4 in s)
print(5 in s)
True False

5.3. Reuniunea

Operatorul | realizează reuniunea a două mulțimi.

a = {1, 2, 3}
b = {3, 4, 5}

print(a | b)

Rezultatul conține elementele care apar în cel puțin una dintre cele două mulțimi.

{1, 2, 3, 4, 5}

5.4. Intersecția

Operatorul & realizează intersecția.

a = {1, 2, 3}
b = {3, 4, 5}

print(a & b)

Elementul comun este 3.

{3}
Exemplul 1 — Eliminarea valorilor duplicate
a = [2, 5, 2, 7, 5, 2]

s = set(a)

print(s)

Lista conține repetări, dar mulțimea păstrează doar valorile distincte.

Exemplul 2 — Elementele comune
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}

comune = a & b

print(comune)
{3, 4}
Exemplul 3 — Reuniunea
a = {1, 2, 3}
b = {4, 5}

toate = a | b

print(toate)
{1, 2, 3, 4, 5}

6. Dicționare

dict cheie valoare frecvențe

6.1. Ce este un dicționar?

Definiție: Un dicționar este o structură de date care memorează informații sub forma unor perechi cheie → valoare.

De exemplu:

note = {
    "Ana": 10,
    "Mihai": 8,
    "Dan": 7
}

Putem interpreta datele astfel:

"Ana"   → 10
"Mihai" → 8
"Dan"   → 7

6.2. Cheia și valoarea

În:

"Ana": 10
  • "Ana" este cheia;
  • 10 este valoarea.

6.3. Accesarea unei valori

print(note["Ana"])

Python caută cheia "Ana" și returnează valoarea asociată acesteia.

10
Exemplul 1 — Citirea unei valori
note = {
    "Ana": 10,
    "Mihai": 8
}

print(note["Ana"])
print(note["Mihai"])
10 8

6.4. Adăugarea unei perechi

note = {}

note["Ana"] = 10
note["Mihai"] = 8

Acum dicționarul conține două perechi.

Exemplul 2 — Adăugare și modificare
note = {}

note["Ana"] = 10
note["Mihai"] = 8

note["Ana"] = 9

print(note)

A doua atribuire pentru "Ana" modifică nota. Nu creează o a doua cheie "Ana".

6.5. Verificarea existenței unei chei

if "Mihai" in note:
    print(note["Mihai"])

Operatorul in verifică dacă cheia există în dicționar.

6.6. Parcurgerea unui dicționar

for nume in note:
    print(nume, note[nume])

La fiecare pas, variabila nume primește o cheie. Cu note[nume] obținem valoarea asociată.

Exemplul 3 — Frecvența valorilor
a = [2, 3, 2, 5, 3, 2]

frecvente = {}

for x in a:

    if x in frecvente:
        frecvente[x] = frecvente[x] + 1

    else:
        frecvente[x] = 1

print(frecvente)

Dicționarul va memora:

2 → 3
3 → 2
5 → 1

Astfel putem afla de câte ori apare fiecare valoare.

6.7. Funcție care calculează frecvențele

def frecvente(a):

    f = {}

    for x in a:

        if x in f:
            f[x] = f[x] + 1

        else:
            f[x] = 1

    return f


a = [2, 3, 2, 5, 3, 2]

print(frecvente(a))

Aici folosim simultan:

  • funcții;
  • parametri;
  • variabile locale;
  • liste;
  • dicționare;
  • structuri repetitive;
  • condiții;
  • return.

7. Recursivitate

recursivitate caz de bază apel recursiv factorial

7.1. Ce este recursivitatea?

Definiție: O funcție este recursivă dacă, în timpul execuției sale, se apelează pe ea însăși.

De exemplu:

def f(n):
    f(n - 1)

Funcția f apelează din nou funcția f.

Acest exemplu este incomplet și nu trebuie executat deoarece funcția nu are o condiție care să îi spună când să se oprească.

7.2. Cazul de bază

O funcție recursivă are nevoie de o situație în care se oprește. Aceasta se numește caz de bază.

def f(n):

    if n == 0:
        return

    f(n - 1)

Când n devine 0, nu mai facem un apel recursiv.

7.3. Cazul recursiv

Partea:

f(n - 1)

este cazul recursiv.

Pentru ca recursivitatea să funcționeze, trebuie ca fiecare apel să se apropie de cazul de bază.

7.4. Exemplul 1 — Factorial

Factorialul unui număr natural pozitiv este:

n! = n × (n - 1) × (n - 2) × ... × 1

De asemenea:

0! = 1

Putem observa relația:

n! = n × (n - 1)!

Această formulă este potrivită pentru recursivitate.

def factorial(n):

    if n == 0:
        return 1

    return n * factorial(n - 1)


print(factorial(5))

Urmărim apelurile:

factorial(5)
    ↓
5 * factorial(4)
    ↓
5 * 4 * factorial(3)
    ↓
5 * 4 * 3 * factorial(2)
    ↓
5 * 4 * 3 * 2 * factorial(1)
    ↓
5 * 4 * 3 * 2 * 1 * factorial(0)

Ajungem la cazul de bază:

factorial(0) = 1

Apoi rezultatele se întorc:

factorial(1) = 1
factorial(2) = 2
factorial(3) = 6
factorial(4) = 24
factorial(5) = 120
120

7.5. Exemplul 2 — Suma numerelor de la 1 la n

Dorim:

1 + 2 + 3 + ... + n

Putem scrie:

suma(n) = n + suma(n - 1)

Cazul de bază:

suma(0) = 0
def suma(n):

    if n == 0:
        return 0

    return n + suma(n - 1)


print(suma(5))

Calculul este:

5 + 4 + 3 + 2 + 1 + 0 = 15
15

7.6. Exemplul 3 — Numărul de cifre

Pentru numărul:

52731

avem 5 cifre.

Dacă eliminăm ultima cifră folosind:

n // 10

obținem:

52731 → 5273 → 527 → 52 → 5

Putem defini funcția:

def numar_cifre(n):

    if n < 10:
        return 1

    return 1 + numar_cifre(n // 10)


print(numar_cifre(52731))
5

7.7. Exemplul 4 — Suma cifrelor

Pentru:

527

dorim:

5 + 2 + 7 = 14

Ultima cifră poate fi obținută cu:

n % 10

Iar numărul fără ultima cifră:

n // 10

Prin urmare:

def suma_cifre(n):

    if n == 0:
        return 0

    return n % 10 + suma_cifre(n // 10)


print(suma_cifre(527))

Urmărirea:

527 % 10 = 7
52 % 10  = 2
5 % 10   = 5

Deci:

7 + 2 + 5 = 14
14

7.8. Cele două întrebări obligatorii la orice recursivitate

Când întâlnim o problemă recursivă, trebuie să ne întrebăm:

Întrebarea 1: Care este cazul de bază?
Întrebarea 2: Cum transform problema într-o problemă mai mică?

Dacă nu putem răspunde la aceste două întrebări, probabil că soluția recursivă nu este încă bine construită.

7.9. Greșeală: recursivitate infinită

def f(n):
    return f(n)

Funcția se apelează cu exact aceeași valoare și nu se apropie niciodată de un caz de bază.

O altă problemă:

def f(n):

    if n == 0:
        return 0

    return f(n + 1)

Dacă pornim cu 5:

5 → 6 → 7 → 8 → 9 → ...

Ne îndepărtăm de cazul de bază 0.

O funcție recursivă trebuie să se apropie de cazul de bază.

8. Probleme de sinteză

În problemele reale, noțiunile nu apar separat. Este foarte posibil să trebuiască să folosim mai multe concepte în aceeași problemă.

Problema 1 — Suma elementelor unui vector

Se dă o listă de numere. Să se calculeze suma elementelor.

def suma_vector(a):

    s = 0

    for x in a:
        s = s + x

    return s


a = [2, 5, 7, 1]

print(suma_vector(a))

Funcția primește lista prin parametrul a.

Variabila s este locală.

Pentru fiecare element x, acesta este adăugat la sumă.

La final, return s trimite rezultatul.

15

Problema 2 — Maximul unui vector

def maxim_vector(a):

    m = a[0]

    for x in a:
        if x > m:
            m = x

    return m


a = [4, 9, 2, 8]

print(maxim_vector(a))

Pornim de la primul element ca valoare maximă presupusă.

Apoi verificăm fiecare element.

Dacă găsim unul mai mare, actualizăm maximul.

9

Problema 3 — Numărul de vocale

def numar_vocale(s):

    nr = 0

    for c in s:

        if c in "aeiouAEIOU":
            nr = nr + 1

    return nr


s = input()

print(numar_vocale(s))

Funcția primește un șir de caractere. Parcurgem fiecare caracter și verificăm dacă este vocală.

Problema 4 — Funcție care verifică dacă un număr este par

def este_par(n):
    return n % 2 == 0


n = int(input())

if este_par(n):
    print("DA")
else:
    print("NU")

Funcția nu afișează nimic. Ea returnează True sau False.

Programul principal decide apoi ce mesaj afișează.

Problema 5 — Factorial

def factorial(n):

    if n == 0:
        return 1

    return n * factorial(n - 1)


n = int(input())

print(factorial(n))

Aici avem o funcție recursivă.

Cazul de bază este:

n == 0

iar cazul recursiv este:

n * factorial(n - 1)

Recapitulare — ce trebuie să știm din Partea 3?

Funcții

  • Știm ce este o funcție.
  • Știm să definim o funcție folosind def.
  • Știm să apelăm o funcție.
  • Știm că definirea și apelarea sunt lucruri diferite.

Parametri și argumente

  • Știm ce este un parametru.
  • Știm ce este un argument.
  • Știm diferența dintre ele.
  • Știm să folosim mai mulți parametri.

Variabile

  • Știm ce este o variabilă locală.
  • Știm ce este o variabilă globală.
  • Înțelegem domeniul unei variabile.
  • Știm de ce parametrii sunt locali funcției.

return

  • Știm că return transmite o valoare din funcție.
  • Știm diferența dintre return și print().
  • Știm să folosim rezultatul unei funcții într-un alt calcul.

Tupluri

  • Știm ce este un tuplu.
  • Știm să accesăm elementele prin index.
  • Știm să parcurgem un tuplu.
  • Știm ce este despachetarea.

Mulțimi

  • Știm că mulțimile păstrează elemente distincte.
  • Știm operatorul in.
  • Știm reuniunea |.
  • Știm intersecția &.

Dicționare

  • Știm ce este o cheie.
  • Știm ce este o valoare.
  • Știm să accesăm o valoare folosind cheia.
  • Știm să adăugăm și să modificăm perechi.
  • Știm să verificăm existența unei chei.
  • Știm să folosim dicționare pentru frecvențe.

Recursivitate

  • Știm ce este o funcție recursivă.
  • Știm ce este cazul de bază.
  • Știm ce este cazul recursiv.
  • Știm de ce recursivitatea trebuie să se apropie de cazul de bază.
  • Știm să construim funcții recursive simple.
Ideea centrală a Părții 3: funcțiile ne permit să împărțim o problemă mare în bucăți mai mici, reutilizabile și ușor de verificat. Parametrii transmit date către funcții, iar return transmite rezultatele înapoi. Tuplurile, mulțimile și dicționarele ne permit să reprezentăm diferite tipuri de date, iar recursivitatea ne permite să rezolvăm anumite probleme prin reducerea lor la versiuni mai mici ale aceleiași probleme.