Programació Funcional en Python
El concepte / paradigma de la programació funcional fa referència a un estil de programació que utilitza les funcions com a unitat bàsica de codi.
Hi ha des de llenguatges purament funcionals com ara Haskell o Lisp, fins a llenguatges multiparadigma com Python, així que no és tan fàcil separar els llenguatges que suporten la programació funcional.
Perquè un llenguatge permeti la programació funcional, ha de tractar les funcions com a ciutadans de primera classe. És el que passa amb Python; les funcions són objectes, igual que els strings, els números i les llistes.
Molts llenguatges donen suport a la programació funcional; com Javascript, C#, PHP i Java.
Anem a veure els conceptes més importants per entendre aquest paradigma.
Funcions pures.
Aquest paradigma tracta d’emprar el màxim possible de funcions pures (almenys una segur que hi ha)
Funcions pures:
- Sol llegeix els seus paràmetres d’entrada
- Sol escriu els seus paràmetres de sortida
- Pels mateixos paràmetres d’entrada sempre retorna els mateixos paràmetres de sortida.
- No tenen efectes colaterals fora de la funció.
Exemple funció pura:
return *2
# let's test
assert == 8Només podrem cridar funcions dins d’altres funcions sempre i quan siguin pures.
Exemple funció impura.
=
= ,
return
, ` global `.
:
```
returnPros:
- Són les funcions més reutilitzables.
- Més testejables.
És important que les funcions no tinguin gaires línies en general.
Encara que no usem Programació Funcional, val la pena usar funcions pures per minimitzar errors.
Funcions d’ordre superior.
A partir d’una funció pura i una col·lecció (llista, diccionari …) podem aplicar funcions d’ordre dintre dels seus elements.
Ens estalvien usar bucles, i a més a més són més elegants.
Les més habituals són:
- map, per editar tots els vaqlors
- filter, per filtrar un subconjunt.
- reduce, va bé per agrupar valors, però s’utilitza menys.
- zip, s’utilitza si volem treballar amb tuples.
Més endavant veurem que altres llibreries de dades, com Pandas, accepten funcions pures per recalcular les seves variables.
Ara toca veure amb exemples les possibilitats que ens ofereixen :)
Map.
Crea una llista de números i una funció per multiplicar per 3 un número; per tal que es mostrin per pantalla tots els números de la llista multiplicats per 3.
return * 3
# range genera sequències de números
# range (num_ini, num_fin, step)
: =
=
Filter.
Crea una llista de números (pex de notes d’alumnat) i una funció per a comprovar si el número és major o igual a 5, i fes que es mostrin per pantalla únicament els números de la llista majors o iguals que 5. Finalment, calcula el percentatge de números filtrats (els >=5) arrodonit a 2 decimals.
return >= 5
: =
=
# Dividim la longitud de les notes >5 respecte el total de notes
# La funció len ens permet veure el número d'elements de les llistes.
: = /
## Per arrodonir a 2 decimals usem funció round.
Fixa’t on està la màgia:
-
filter la funció d’ordre superior
-
greaterOrEqual5 nom de la funció
-
llistaNotes nom de la llista on volem aplicar la funció.
-
list per comoditat el resultat el retornem com a llista.
Podem realitzar una implementació més genèrica i flexible:
return >= 5
return >= 0
: =
=
return
Exercici Filter. Crea una llista de números (pex de notes d’alumnat) i una funció per a comprovar si el número és major o igual a 5, i fes que es mostrin per pantalla únicament els números de la llista majors o iguals que 5. Finalment, calcula el percentatge de números filtrats (els >=5) arrodonit a 2 decimals.
Exemple de llista de notes: llistaNotes: list[float] = [8,5,6.2,4.2,10,6.8,3.4,7.9,9.3,8,2.4,9.7,7.6]
{% sol %}
return >= 5
: =
=
# Dividim la longitud de les notes >5 respecte el total de notes
# La funció len ens permet veure el número d'elements de les llistes.
: = /
## Per arrodonir a 2 decimals usem funció round.
Resultat: Llista notes original. [8, 5, 6.2, 4.2, 10, 6.8, 3.4, 7.9, 9.3, 8, 2.4, 9.7, 7.6] Llista notes majors o iguals a 5. [8, 5, 6.2, 10, 6.8, 7.9, 9.3, 8, 9.7, 7.6] Percentatge aprovats. 76.92 %
{% endsol %}
zip.
Tenim una llista de noms de països i una altra amb la seva població. Volem que es crei una llista hi hagi una tupla amb el nom i població de cada país. Així podrem iterar tota la informació d’un sol cop.
=
=
# [('China', 1391), ('India', 1364), ('Estados Unidos', 327), ('Indonesia', 264)]
# També serveix per crear diccionaris.
=
Repte: Com s’implementaria el zip de Python a mà ?
{% sol %}
=
=
=
## Si el tamany de les llistes és diferent
## fem que tinguin el mateix tamany
=
=
# Fusionem les 2 llistes en una tupla ( )
# Si volguessim un diccionari en comptes d'una tupla
# result.append({lis1[num],lis2[num]})
return
{% endsol %}
Reduce.
Tenim una llista de números, i volem calcular el producte de tots els números, en un únic valor
=
# Salida: 24En aquest exemple veiem el concepte de funció anònima o Lambda.
lambda x, y: x * y
Funcions lambda (anònimes)
En ocasions no ens interessa tenir una funció creada per un sol cop que volem usar el codi. Per exemple, si únicament la volem per a fer map, filter… ens podem estalviar crear una funció amb nom i declarar-la com a anònima amb la paraula lambda.
Així, també millorem el rendiment.
Veiem un exemple senzill de funció lambda aplicat a la funció map:
# Lambda. Llista números multiplicats per 5.")
# Retorna:
# [15, 20, 40, 50]Referències.
Referències: