Type to search…

Funcions

Les funcions són blocs de codi que es poden reutilitzar en altres parts del codi.

Funcions

Una manera molt útil d’organitzar el flux d’execució del programa és agrupant un tros de codi en una funció per tal que el puguem cridar en diferents parts del codi sense haver-lo de repetir.

Python disposa de diverses funcions predefinides, com el print, el len()

Ara aprendrem a crear les nostres pròpies funcions.

En qualsevol projecte informàtic rellevant és fonamental usar funcions i separar-les en diversos Mòduls i/o Objects (que ho veureu una mica més endavant).

Una funció en Python utilitza el mateix concepte que una funció matemàtica.

La capçalera està composta per:

  • La paraula reservada def
  • el nom de la funció
  • els paràmetres d’entrada entre parèntesis ()
  • i al final :

El cos de la funció té les instruccions que volem i si ho volem la paraula return i una variable o estructura.

No estem obligats a aplicar cap return, però ens interessa usar un return per a què la funció sigui pura.

Potser et preguntaràs si falten els paràmetres de sortida a la capçalera. No calen.

Anem a veure un parell d’exemples molt simples:

potencia(x, y) = x ^ y

python
def potencia(num, pot):
  return num ** pot

print("3 ^ 2 = ", potencia(3,2))
print("2 ^ 20 = ", potencia(2,20))

Per provar que realment funciona apliquem uns testos amb assert

python
assert potencia(3,2) == 9
assert potencia(3,2) == 1048576

cognom1_cognom2_nom(name, surname1, surname2=“”)

És una funció que mostra un nom i 2 cognoms en l’ordre cognom1 cognom2, nom

Fixa’t que hem definit el paràmetre surname2 com a opcional, si l’usuari no posa res a surname2 s’omple automàticament amb un espai en blanc.

python
def cognom1_cognom2_nom(name, surname1, surname2=""):
    if surname2:
        return f"{surname1} {surname2}, {name}"
    else:
        return f"{surname1}, {name}"

print(cognom1_cognom2_nom("Ana","Santos","Oliveira"))
print(cognom1_cognom2_nom("Haruto","Sato"))

Funcions dins de funcions.

Per tal de descompondre un problema complex en d’altres més petits i senzills podem cridar una funció dins d’una altra funció si ens cal, com es pot veure a l’exemple.

python
def calculate_area(length, width):
    return length * width

def calculate_volume(length, width, height):
    base_area = calculate_area(length, width)
    return base_area * height

length = 5
width = 3
height = 10

print(f"Area: {calculate_area(length, width)}")  # Output: Area: 15
print(f"Volume: {calculate_volume(length, width, height)}")  # Output: Volume: 150

Paràmetres opcionals.

En moltes ocasions, ens interessa simplificar la crida de les funcions, fent que alguns paràmetres tinguin un valor predeterminat, i que, per tant, no calgui omplir-los si tenen aquest valor predeterminat.

És tan fàcil com ficar el valor predeterminat al costat del paràmetre:

python
def greet(name="stranger"):
    return "Hello, " + name + "!"

Ho provarem:

python
assert greet() == "Hello, stranger!"
assert greet(name="Miquel") == "Hello, Miquel!"

Docstring.

Per comentar una funció usem aquesta notació; abans del cos:

python
def foo():
    """A multi-line
    docstring.
    """
    # sentences

Exercicis.

1. Crea un mètode (funció sense valors de retorn) que agafi el nom i la edat d’una persona.

Si la persona és menor de 16 anys es mostrarà:

shell
Ets massa jove per entrar al club de les tortugues.

En canvi, si té 16 o més anys es mostrarà:

shell
Benvigut al club, Aida 🐢
Show solution
python
def club_tortugues(nom, edat):
    """
    Mostra un missatge segons si la persona pot entrar al club de les tortugues.
    """
    if edat < 16:
        print("Ets massa jove per entrar al club de les tortugues.")
    else:
        print(f"Benvigut al club, {nom} 🐢")

2. Crea una funció per calcular el preu d’un producte.

Tindrà 3 paràmetres: el preu, l’IVA (opcional), que per defecte serà el 21% i el descompte (opcional), que per defecte serà 0.

Prova el codi mitjançant asserts (tests).

python
def preu_final(preu_total, descompte=0.0, iva=0.21):
  """
     calcular el preu d'un producte. Tindrà 3 paràmetres: 
     - preu (obligatori)
     - descompte(opcional), que per defecte serà 0.0
     - IVA en decimals(opcional) que per defecte serà el 0.21 
  """
  return preu_total - preu_total * descompte + preu_total * iva

# print(f"{preu_final(100)}")
assert preu_final(100) == 121.0
assert preu_final(100,0.2) == 101.0
assert preu_final(100,0.1,0.04) == 94.0
Show solution
python
# Exercici 2: Preu final amb IVA i descompte
def preu_final(preu_total, descompte=0.0, iva=0.21):
    """
    Calcula el preu final d'un producte.
    """
    return preu_total - preu_total * descompte + preu_total * iva

3. Crea una funció que calculi la mitjana aritmètica d’una llista de números (per exemple, edats).

Prova el codi mitjançant 2 o 3 asserts (tests).

Revisa el tutorial https://xtec.dev/python/list

Show solution
python
# Exercici 3: Mitjana aritmètica d'una llista
def mitjana_llista(nums):
    """
    Calcula la mitjana aritmètica d'una llista de números.
    Retorna None si la llista és buida.
    """
    if not nums:
        return None
    return sum(nums) / len(nums)

# Tests
assert mitjana_llista([10, 20, 30]) == 20.0
assert mitjana_llista([5, 15, 25, 35]) == 20.0
assert mitjana_llista([]) is None

4. Crea un mètode que cerqui dins d’un diccionari totes les dades d’una persona si existeix.

Si no existeix que surti el text “No s’ha trobat la persona”.

El diccionari d’exemple que pots usar és el següent:

python
persons = [
    {"nom": "Eva", "cognom": "Vilaregut", "sexe": "Dona", "edat": 19, "altura": 163},
    {"nom": "Joan", "cognom": "Martinez", "sexe": "Home", "edat": 25, "altura": 173},
    {"nom": "Raquel", "cognom": "Viñales", "sexe": "Dona", "edat": 13, "altura": 153},
    {"nom": "Esther", "cognom": "Parra", "sexe": "Dona", "edat": 33, "altura": 178},
    {"nom": "Laura", "cognom": "Casademunt", "sexe": "Dona", "edat": 41, "altura": 182},
    {"nom": "Marc", "cognom": "Sales", "sexe": "Home", "edat": 16, "altura": 176},
]

Si necessites usar assets, aquí en tens algún:

python
# Tests
assert cerca_persona("Eva") == {"nom": "Eva", "cognom": "Vilaregut", "sexe": "Dona", "edat": 19, "altura": 163}
assert cerca_persona("Marc") == {"nom": "Marc", "cognom": "Sales", "sexe": "Home", "edat": 16, "altura": 176}
assert cerca_persona("Xavi") == "No s'ha trobat la persona"

Revisa el tutorial https://xtec.dev/python/data

Show solution
python
def cerca_persona(nom_buscar):
    """
    Retorna les dades d'una persona si existeix en la llista de diccionaris.
    Si no, retorna un missatge indicant que no s'ha trobat.
    """
    for persona in persons:
        # Usem lower per a què converteixi la entrada en minúsucules.
        if persona["nom"].lower() == nom_buscar.lower():
            return persona
    return "No s'ha trobat la persona"

Type Hinting

Des de fa uns anys s’utilitza el Type Hinting en Python, per informar els programadors els tipus de dades de cara variable, paràmetres i valors de retorn.

És important que us acostumeu a veure-ho i probablement us ho demanen com a bona pràctica d’estil de codificació.

La pròxima funció la definirem amb aquests Type Hinting; van entre 2 punts en variables i arguments, i tenen una fletxeta en els paràmetres de sortida.

python
def potencia(num: float, pot: float) -> float:
  return num ** pot

print("2 ^ 20 = ", potencia(2,20))
print("2 ^ 20 = ", potencia(4.5,3))

Per aprofundir en l’ús de funcions, segueix llegint:

Funcions pures.

Per tal de crear funcions senzilles d’entendre’s i de provar automàticament (per exemple, amb Pytest) han de complir el necessari per a ser 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 col·laterals fora de la funció.

Exemple funció pura:

python
def mult2(i: float) -> float: 
    return i*2

# let's test
assert mult2(4) == 8

Només podrem cridar funcions dins d’altres funcions sempre que siguin pures. I només podem testejar funcions pures.

Exemple funció impura.

python
name = 'John'
def greetings_from_outside():
  name = 'aaaa',name
  return(f"Greetings from {name}")

És impura perquè està escrivint la sortida amb variables de fora de la funció, utilitza una variable global name.

La podem arreglar:

python
def greetings_from_outside(name: str):
  return(f"Greetings from {name}")

Una altra recomanació és que les funcions no tinguin gaires línies en general.


Exercicis

1. L’ADN es pot representar amb un str, i les bases amb els caràcters "A", "G", "C" i "T".

Crea una funció que calculi l’aparició d’una de les bases:

Show solution
python
def adn_count_base(adn, base):
    """Compta el número d'aparicions de la base"""
    counter = 0
    for x in adn:
        if x == base:
            counter += 1

    return counter

Crea una funció que calculi el percentage GC (el d’aparició de G i C):

Show solution
python
def adn_percent_gc(adn):
    """Retorna el percentatge GC"""
    counter = 0
    for x in adn:
        if x == "G" or x == "C":
            counter += 1
    
    percent = round(counter / len(adn), 4)

    return percent 

Pending