Programare functionala
Chiar daca limbajul Python este catalogat ca facand parte din categoria limbajelor de programare orientate pe obiecte, la nivelul lui sunt disponibile si elemente care permit implementari ale unor alte paradigme de programare, precum paradigma functionala.
Programare functionala reprezinta o metoda de proiectare si dezvoltare a aplicatiilor bazata pe evaluarea de expresii care nu au in vedere modificarea starii. In cadrul acestui stil de programare codul este oferit prin intermediul functiilor. Programarea functionala promoveaza un cod fara efecte secundare, fara modificari ale starii variabilelor.
# stil ne-functional >>> nume = 'Ghita' >>> nume = "{} Ionescu".format(nume) >>> nume 'Ghita Ionescu'
# stil functional >>> prenume = 'Ghita' >>> nume = "{} Ionescu".format(prenume) >>> nume 'Ghita Ionescu'
In limbajul Python, functiile sunt tratate ca si obiecte de ordinul intai (first class objects). Sunt permise urmatoarelor operatii cu functii: o functie poate avea ca si argumente alte functii; o functie poate fi returnata ca si rezultat al unei alte functii.
def aduna_doua_numere(x, y): return x + y def aduna_trei_numere(x, y, z): return x + y + z def functie_adecvata(numar_elemente): if numar_elemente == 2: return aduna_doua_numere else: return aduna_trei_numere
>>> args = [1, 2, 3] >>> numar_elemente = len(args) >>> rezultat = functie_adecvata(numar_elemente) >>> rezultat <function aduna_trei_numere at 0x03655DB0> >>> rezultat(*args) 6
>>> args = [1, 2] >>> numar_elemente = len(args) >>> rezultat = functie_adecvata(numar_elemente) >>> rezultat <function aduna_doua_numere at 0x0125C660> >>> rezultat(*args) 3
Expresii lambda
Expresiile lambda permit crearea de functii anonime cu ajutorul cuvantului cheie lambda. Sintaxa unei expresii lambda urmeaza indeaproape sintaxa de definire a unei functii (def).
Intr-o expresie lambda sunt precizate argumente – inainte de caracterul : – si o expresie returnata (chiar daca nu explicit). Unei expresii lambda ii pot corespunde mai multe argumente, dar numai o singura expresie, care este evaluata si returnata.
lambda argumente: expresie
Daca o expresie lambda este referita de o variabila, atunci ea are un comportament similar unei functii, si poate fi apelata in mod asemanator.
>>> insumare = lambda a, b: a + b >>> insumare(1, 2) 3
Daca expresia lambda nu este referita de o variabila, atunci ea poarta numele de functie anonima (functie fara nume). Acestea sunt des utilizate in combinatie cu functiile de nivel inalt map(), reduce() si filter().
>>> def f(a, b): ... return a + b ... >>> f(1, 3) 4
>>> f = lambda a, b: a + b >>> f(1, 3) 4
>>> def al_doilea(element): ... return element[1] ... >>> studenti = [('Marian', 7.21), ('Ioana', 8.34), ('Paul', 6.72), ('Zaya', 9.45)] >>> sorted(studenti) [('Ioana', 8.34), ('Marian', 7.21), ('Paul', 6.72), ('Zaya', 9.45)] >>> sorted(studenti, key = al_doilea) [('Paul', 6.72), ('Marian', 7.21), ('Ioana', 8.34), ('Zaya', 9.45)] >>> sorted(studenti, key = lambda x : x[1]) [('Paul', 6.72), ('Marian', 7.21), ('Ioana', 8.34), ('Zaya', 9.45)] >>> sorted(studenti, key = lambda x : x[1], reverse = True) [('Zaya', 9.45), ('Ioana', 8.34), ('Marian', 7.21), ('Paul', 6.72)]
Map
Functia map() primeste ca si argumente o functie si una sau mai multe colectii de elemente iterabile si creeaza o noua colectie de elemente. Ruleaza functia pe fiecare element de la nivelul colectiei (colectiilor) initiale si adauga valorile returnate la nivelul colectiei create.
map(functie, iterabil, ...)
Valoarea returnata (obiect map) poate fi transmisa unor functii precum list(), pentru a crea o lista de elemente, sau set(), pentru a crea o multime de elemente.
>>> orase = ['Timisoara', 'Londra', 'Budapesta', 'New York'] >>> lungime_nume = map(len, orase) >>> lungime_nume <map object at 0x03861950> >>> list(lungime_nume) [9, 6, 9, 8]
>>> numere = (1, 2, 3, 4) >>> rezultat = map(lambda x: x*x, numere) >>> rezultat <map object at 0x03861810> >>> patrate_numere = set(rezultat) >>> patrate_numere {16, 1, 4, 9}
Functia map() poate primi ca si argumente mai multe colectii, atata timp cat acestea beneficiaza de aceeasi dimensiune.
>>> a = [1, 2, 3, 4] >>> b = [11, 12, 13, 14] >>> c = [5, 6, 7, 8] >>> list(map(lambda x, y, z: x + y * z, a, b, c)) [56, 74, 94, 116]
Filter
Functia filter() primeste ca si argumente o functie si o colectie de elemente iterabile si filtreaza elementele colectiei cu ajutorul functiei care testeaza daca fiecare element este evaluat la True sau False
filter(functie, iterabil)
Valoarea returnata (obiect filter) contine un obiect iterabil, al carui elemente au fost evaluate la True in contextul functiei argument.
>>> orase = ['Timisoara', 'Londra', 'Budapesta', 'New York'] >>> incepe_cu = list(filter(lambda x: x.startswith('T'), orase)) >>> incepe_cu ['Timisoara']
>>> numere = [23, 5, 12, 8, 31, 4, 16] >>> rezultat = filter(lambda x: x % 2 == 1, numere) >>> rezultat <filter object at 0x03861890> >>> numere_impare = set(rezultat) >>> numere_impare {31, 5, 23} >>> rezultat = filter(lambda x: x % 2 == 0, numere) >>> numere_pare = set(rezultat) >>> numere_pare {8, 16, 12, 4}
Reduce
Functia reduce() primeste ca si argumente o functie si o colectie de elemente iterabile si returneaza o valoare calculata prin combinarea elementelor colectiei.
reduce(functie, iterabil)
Primul argument de la nivelul functiei/expresiei lambda poarta numele de acumulator, si reprezinta valoarea returnata prin executia functiei/expresiei lambda cu elementul din iteratia anterioara. Cel de-al doilea argument este elementul din iteratia curenta.
>>> from functools import reduce >>> reduce(lambda a, x : a * x, [1, 2, 3]) 6
Functia reduce() parcurge elementele colectiei furnizate ca si argument. Pentru fiecare element returneaza valoarea functiei/expresiei lambda cu valorile curente ale acumulatorului si elementului curent. In prima iteratie, acumulatorul se initializeaza cu valoarea primului element al colectiei, dupa care se trece la urmatoarea iteratie.
>>> numere = [1, 2, 3, 4] >>> suma = reduce(lambda x, y : x + y, numere) >>> suma 10
>>> numere = [23, 45, 11, 7] >>> max = reduce(lambda a, b: a if a > b else b, numere) >>> max 45
Daca valoarea primului element al colectiei nu poate fi utilizata pentru acumulator, aceasta poate fi specificata folosind un al treilea argument al functiei reduce().
>>> orase = ['Timisoara', 'Londra', 'Budapesta', 'New York'] >>> numara_a = reduce(lambda a, x: a + x.count('a'), orase, 0) >>> numara_a 5