giovedì 16 ottobre 2025

Corso di Python: 4 – Funzioni

4 – Funzioni

Obiettivi

  • Capire che cos’è una funzione e quando usarla.

  • Creare funzioni con parametri e valori di ritorno.

  • Usare funzioni anonime (lambda).

  • Comprendere lo scope delle variabili (locale vs globale).

  • Realizzare una funzione che calcoli il fattoriale (diverse implementazioni) con esempi eseguibili.


1. Che cos’è una funzione

Una funzione è un blocco di codice riutilizzabile che esegue un compito specifico. Favorisce modularità, leggibilità e riuso.

def saluta():
    print("Ciao!")

Chiamare la funzione:

saluta()   # output: Ciao!

2. Creazione di funzioni: sintassi di base

def nome_funzione(param1, param2):
    """
    Docstring: descrizione breve della funzione.
    """
    risultato = param1 + param2
    return risultato

Esempio:

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

print(somma(3, 5))   # 8

3. Parametri: tipi e comportamento

Parametri posizionali

def moltiplica(a, b):
    return a * b

print(moltiplica(4, 5))  # 20

Parametri con valore di default

def saluto(nome="Amico"):
    return f"Ciao, {nome}!"

print(saluto())          # Ciao, Amico!
print(saluto("Luca"))    # Ciao, Luca!

Parametri keyword (nominali)

def concat(a, b):
    return f"{a}-{b}"

print(concat(b="mondo", a="ciao"))  # ciao-mondo

Parametri variabili: *args e **kwargs

def somma_tutti(*args):
    return sum(args)

print(somma_tutti(1,2,3,4))  # 10

def stampa_info(**kwargs):
    for k, v in kwargs.items():
        print(k, "=", v)

stampa_info(nome="Anna", eta=30)
# nome = Anna
# eta = 30

4. Valori di ritorno multipli

In Python è possibile restituire una tupla.

def quoziente_resto(a, b):
    q = a // b
    r = a % b
    return q, r

q, r = quoziente_resto(17, 5)
print(q, r)   # 3 2

5. Funzioni anonime (lambda)

Le lambda sono funzioni in una riga, utili per funzioni semplici o come argomenti.

doppio = lambda x: x * 2
print(doppio(5))  # 10

# usata con map
nums = [1, 2, 3, 4]
dopp = list(map(lambda x: x*2, nums))
print(dopp)  # [2,4,6,8]

Nota: per operazioni complesse preferire def con nome e docstring.


6. Scope delle variabili: locale vs globale

  • Variabile locale: definita dentro la funzione, visibile solo lì.

  • Variabile globale: definita fuori; accessibile in lettura dentro la funzione, ma per modificarla serve global.

Esempi:

x = 10  # globale

def leggi():
    print(x)  # 10 - lettura consentita

def modifica():
    global x
    x = 20    # modifica la variabile globale

leggi()
modifica()
leggi()  # ora stampa 20

Meglio evitare l'eccesso di variabili globali: preferire parametri e valori di ritorno.


7. Docstring e typing hints (buone pratiche)

def area_rettangolo(base: float, altezza: float) -> float:
    """Restituisce l'area di un rettangolo."""
    return base * altezza

print(area_rettangolo(3.5, 2))  # 7.0

Le annotazioni : float e -> float sono consigliate per leggibilità e supporto editoriale, ma non sono obbligatorie.


8. Esempi pratici: funzioni utili

Validazione email (semplice)

import re

def is_email(s: str) -> bool:
    pattern = r'^\S+@\S+\.\S+$'
    return bool(re.match(pattern, s))

print(is_email("luca@example.com"))  # True
print(is_email("notaemail"))         # False

Funzione ricorsiva: potenza

def potenza(base: float, esp: int) -> float:
    if esp == 0:
        return 1
    elif esp > 0:
        return base * potenza(base, esp - 1)
    else:
        return 1 / potenza(base, -esp)

9. Esercizio principale: funzione che calcola il fattoriale

Descrizione: calcolare n! = n × (n-1) × ... × 1 per interi non negativi n. Definire più implementazioni e mostrare esempi numerici.

9.1 Fattoriale iterativo (raccomandato per produzione)

def factorial_iter(n: int) -> int:
    """
    Calcola il fattoriale in modo iterativo.
    Solleva ValueError per n < 0.
    """
    if n < 0:
        raise ValueError("n deve essere >= 0")
    result = 1
    for i in range(2, n+1):
        result *= i
    return result

# Esempi
print(factorial_iter(0))  # 1
print(factorial_iter(1))  # 1
print(factorial_iter(5))  # 120
print(factorial_iter(10)) # 3628800

9.2 Fattoriale ricorsivo (più elegante, attenzione allo stack)

def factorial_rec(n: int) -> int:
    if n < 0:
        raise ValueError("n deve essere >= 0")
    if n == 0 or n == 1:
        return 1
    return n * factorial_rec(n - 1)

# Test
print(factorial_rec(6))  # 720

9.3 Fattoriale usando math.factorial

import math
print(math.factorial(7))  # 5040

9.4 Controllo dimensionale / controllo input

Assicurati sempre che l'input sia un intero non negativo:

def factorial_safe(x):
    if not isinstance(x, int):
        raise TypeError("Il valore deve essere un intero")
    return factorial_iter(x)

Esempio completo con gestione eccezioni:

try:
    print(factorial_safe(5))   # 120
    print(factorial_safe(-1))  # solleva ValueError
except Exception as e:
    print("Errore:", e)

10. Esercizi proposti (con soluzioni sintetiche indicate)

  1. Scrivi una funzione is_prime(n) che ritorna True se n è primo.

    • Suggerimento: controlla i divisori fino a sqrt(n).

  2. Scrivi una funzione gcd(a, b) (Massimo Comune Divisore) usando l'algoritmo di Euclide.

    def gcd(a, b):
        while b:
            a, b = b, a % b
        return abs(a)
    
  3. Scrivi factorial_tail(n, acc=1) versione ricorsiva in coda (tail recursion). Nota: Python non ottimizza la tail recursion, ma è un buon esercizio concettuale.

  4. Scrivi una funzione apply_twice(f, x) che applica la funzione f due volte a x. Usa lambda per test.

    def apply_twice(f, x):
        return f(f(x))
    
    print(apply_twice(lambda y: y+3, 4))  # 10
    

11. Note finali e best practice

  • Preferire implementazioni iterative per problemi come il fattoriale se la profondità di ricorsione può essere grande.

  • Documenta ogni funzione con docstring e fornisci esempi di utilizzo.

  • Usa typing hints per chiarezza.

  • Evita di modificare variabili globali all'interno delle funzioni: preferisci parametri e ritorni.

  • Scrivi test semplici (assert) per verificare il comportamento atteso.


Nessun commento:

Posta un commento

Corso Fondamenti di Informatica e Reti: 4 Architettura del computer

  ARCHITETTURA DEL COMPUTER come funziona davvero una macchina Capire un computer non significa solo saperlo accendere o aprire file: die...