Funzioni
- #python
- #programmazione
- #funzioni
In questa lezione
- 1. Introduzione
- 2. Sintassi
- 3. Valore di ritorno
- 4. Chiamare una funzione
- 5. Argomenti
- 5.1 Parametri e Argomenti
- 5.2 Numero di argomenti
- 5.3 Parametri di default
- 5.4 Argomenti per chiave
- 5.5 Argomenti solo posizionali
- 5.5 Argomenti solo per chiave
- 6. *args e **kwargs
- 6.1 *args
- 6.2 **kwargs
- 7. Scope
- 7.1 Variabili locali
- 7.1 Variabili globali
- 8. Decoratori
- 9. Funzioni Lambda
- 10. Funzioni Ricorsive
- 11. Generatori
- 12. Quiz a risposta multipla
- Leggi il codice: cosa stampa? dov’è il bug?
- 13. Esercizi
- 13.1 Esercizio - Funzione Quadrato
- 13.2 Esercizio - Funzione Media
- 13.3 Esercizio - Funzione Ricorsiva
- 13.4 Esercizio - Funzione Generatore
- 13.5 Esercizio - Funzioni e Liste
- 13.6 Esercizio - Funzioni e Dizionario
- 13.7 Esercizio - Gestione avanzata con *args e **kwargs
- 13.8 Esercizio completo - Gioco del Tris (Tic-Tac-Toe)
1. Introduzione
Le funzioni in Python, e in generale in tutti i linguaggi di programmazione, sono sostanzialmente dei blocchi di codice riutilizzabili; possono essere pensate come dei “sottoprogrammi” richiamabili da altri programmi. Grazie alle funzioni è possibile definire dei blocchi di codice che vengono eseguiti unicamente quando vengono richiamati. Le funzioni servono per svolgere molteplici scopi:
- leggibilità
- manutenibilità
- evitare la duplicazione
Immaginiamo di dover eseguire la stessa operazione di conversione della temperatura da Fahrenheit a Celsius diverse volte nello stesso programma.
Senza le funzioni scriveremmo:
temp1 = 77
celsius1 = (temp1 - 32) * 5 / 9
print(celsius1)
temp2 = 95
celsius2 = (temp2 - 32) * 5 / 9
print(celsius2)
temp3 = 50
celsius3 = (temp3 - 32) * 5 / 9
print(celsius3)
Con le funzioni:
def fahrenheit_to_celsius(fahrenheit):
return (fahrenheit - 32) * 5 / 9
print(fahrenheit_to_celsius(77))
print(fahrenheit_to_celsius(95))
print(fahrenheit_to_celsius(50))
2. Sintassi
La sintassi di una funzione in in generale è:
def nome_funzione (elenco_parametri):
istruzioni
return valore_restituito
Dove:
- nome_funzione è il nome dato alla funzione, si raccomanda di seguire le stesse regole sintattiche per le variabili.
- elenco_parametri può anche essere una lista vuota, oppure si elencano gli argomenti passati alla funzione detti anche parametri.
- return: è l’istruzione per ritornare un certo risultato al chiamante. Questa istruzione non è obbligatoria.
Nota
È possibile creare una funzione vuota in python (perchè magari non sappiamo ancora come popolarla) usando la parola chiave: pass
def funzione_vuota():
pass 3. Valore di ritorno
- Ogni funzione presenta un valore di ritorno che puo’ essere di qualsiasi tipo predefinito o definito dell’utente.
- Nel caso di funzione che compie un azione, ovvio non deve ritornare nessun valore, non deve effettuare nessun ritorno di valori.
- Una funzione puo’ avere o meno una lista di argomenti.
4. Chiamare una funzione
Per chiamare una funzione basta usare il nome della funzione seguita dalle parentesi:
def saluta():
print("Hello World!")
saluta()
5. Argomenti
Possibile passare dei dati come input alla funzione che si vuole chiamare, a patto che li accetti, inserendoli come argomenti alla chiamata.
def saluta(nome, eta):
print(f"Ciao {nome}, un uccellino mi ha detto che hai {eta} anni")
saluta("Marco", 45)
saluta("Marina", 77)
Attenzione
Nell’esempio precedente non sono stati specificati i tipi delle variabili “nome” e “eta”, quindi il chiamante potrebbe passare qualsiasi cosa. Noi sappiamo per logica che nome dovrebbe essere una stringa e eta dovrebbe essere un valore intero, ma non c’è nessun tipo di forzatura sul tipo richiesto.
Quindi il chiamante potrebbe fare una chiamata di questo tipo, senza beccare nessun tipo di errore:
saluta(789, 'd')Il che non avrebbe nessun senso logico.
Per questa ragione è consigliato (ma non obbligatorio) inserire il tipo di valore (type hint) ai valori nella definizione della funzione:
def saluta(nome: str, eta: int):
print(f"Ciao {nome}, un uccellino mi ha detto che hai {eta} anni")
saluta("Marco", 45) # OK
saluta(789, 'd') # ERORRE 5.1 Parametri e Argomenti
Spesso i termini parametri e argomenti vengono confusi e inverti, ma è necessario al fine di capirsi, conoscere la distinzione.
- Parametro: è la variabile listata nelle parentesi nella definizione della funzione.
- Argomento: è il valore effettivo che viene passato nella chiamata della funzione.
5.2 Numero di argomenti
Per ora è stato dato per scontato, ma di default se la funzione richiede x numero di parametri, allore il chimante dovrà passarli tutti x nel medesimo ordine.
Come fatto per l’esempio precedente della funzione saluta()
5.3 Parametri di default
È possibile però assegnare dei valori di default ai parametri della funzione. In questo caso se il chiamante non fornirà tali argomenti, la funzione assegnerà i valori di default.
def saluta(nome: str, eta: int = 18):
print(f"Ciao {nome}, un uccellino mi ha detto che hai {eta} anni")
saluta("Marco", 45) # OUTPUT: Ciao Marco, un uccellino mi ha detto che hai 45 anni
saluta("Anna") # OUTPUT: Ciao Anna, un uccellino mi ha detto che hai 18 anni
5.4 Argomenti per chiave
È possibile anche chiamare una funzione specificando esplicitamente il nome dei parametri, indipendentemente dall’ordine.
def saluta(nome: str, eta: int):
print(f"Ciao {nome}, hai {eta} anni")
saluta(eta=30, nome="Luca")
Questo rende il codice:
- più leggibile
- meno soggetto a errori quando i parametri sono molti
5.5 Argomenti solo posizionali
In python è possibile forzare alcuni parametri ad essere solo posizionali, usando il simbolo /:
def somma(a, b, /):
return a + b
somma(3, 4) # OK
somma(a=3, b=4) # ERRORE
Tutti i parametri prima di / devono essere passati per posizione.
5.5 Argomenti solo per chiave
Al contrario, possiamo forzare alcuni parametri ad essere passati solo per chiave, usando *.
def login(*, username, password):
print(f"Login di {username}")
login(username="admin", password="1234") # OK
login("admin", "1234") # ERRORE
Tutti i parametri dopo * devono essere specificati con il loro nome.
6. *args e **kwargs
Quando non sappiamo quanti argomenti verranno passati a una funzione, possiamo usare:
- *args argomenti posizionali (tupla)
- **kwargs argomenti per chiave (dizionario)
6.1 *args
def somma(*args):
totale = 0
for numero in args:
totale += numero
return totale
print(somma(1, 2, 3))
print(somma(5, 10, 15, 20))
6.2 **kwargs
def stampa_dati(**kwargs):
for chiave, valore in kwargs.items():
print(f"{chiave}: {valore}")
stampa_dati(nome="Anna", eta=25, citta="Roma")
7. Scope
Lo scope definisce dove una variabile è accessibile.
In genere è sempre preferibile avere variabili locali per avere maggiore controllo delle variabili.
7.1 Variabili locali
Le variabili definite dentro una funzione sono locali:
def funzione():
x = 10
print(x)
funzione()
# print(x) → ERRORE
7.1 Variabili globali
Le variabili definite fuori dalle funzioni sono globali:
x = 5
def funzione():
print(x)
funzione()
Nota
Per modificare una variabile globale dentro una funzione bisogna usare global:
x = 5
def cambia():
global x
x = 10
cambia()
print(x) # 10 8. Decoratori
I decoratori sono funzioni che modificano il comportamento di altre funzioni.
def mio_decoratore(funzione):
def wrapper():
print("Prima della funzione")
funzione()
print("Dopo la funzione")
return wrapper
@mio_decoratore
def saluta():
print("Ciao!")
saluta()
Output:
Prima della funzione
Ciao!
Dopo la funzione
9. Funzioni Lambda
Le lambda sono funzioni anonime, scritte in una sola riga.
somma = lambda a, b: a + b
print(somma(3, 4))
Sono utili per:
- funzioni brevi
map(),filter(),sorted()
Esempio:
numeri = [1, 2, 3, 4]
quadrati = list(map(lambda x: x**2, numeri))
10. Funzioni Ricorsive
Una funzione è ricorsiva quando chiama sé stessa.
Esempio: fattoriale
def fattoriale(n):
if n == 0:
return 1
return n * fattoriale(n - 1)
print(fattoriale(5)) # 120
Ogni funzione ricorsiva deve avere:
- caso base (
return 1nell’esempio sopra) - passo ricorsivo (
return n * fattoriale(n - 1)nell’esempio sopra)
11. Generatori
I generatori permettono di produrre valori uno alla volta usando yield.
def contatore(n):
for i in range(n):
yield i
for numero in contatore(5):
print(numero)
Vantaggi:
- meno memoria
- ideali per grandi sequenze
12. Quiz a risposta multipla
Mettiti alla prova
0/5 risposte
1) A cosa serve una funzione?
2) Cosa restituisce una funzione senza return?
3) Cosa rappresenta *args?
4) Qual è lo scopo di yield?
5) Una funzione ricorsiva deve avere:
Leggi il codice: cosa stampa? dov’è il bug?
Leggi il codice
0/5 risposte
Cosa stampa questo codice?
Cosa stampa?x = 10 def modifica(): x = 20 print(x) modifica() print(x)Cosa stampa questo codice?
Cosa stampa?def conta(*args, **kwargs): print(len(args), len(kwargs)) conta(1, 2, 3, a=4, b=5)Attenzione al valore di default: cosa stampa?
Cosa stampa?def aggiungi(x, lista=[]): lista.append(x) return lista print(aggiungi(1)) print(aggiungi(2))Questa funzione ricorsiva non termina mai. Clicca la riga con il bug.
Trova il bugClicca la riga che contiene l'errore.
def fattoriale(n): if n == 0: return 1 return n * fattoriale(n) print(fattoriale(5))La funzione dovrebbe restituire il numero più grande, ma con questa lista stampa 0. Dov'è il bug?
Trova il bugClicca la riga che contiene l'errore.
def massimo(numeri): m = 0 for n in numeri: if n > m: m = n return m print(massimo([-5, -2, -9])) # atteso: -2
13. Esercizi
13.1 Esercizio - Funzione Quadrato
Scrivi una funzione che calcoli il quadrato di un numero.
13.2 Esercizio - Funzione Media
Scrivi una funzione che accetti un numero variabile di argomenti e ne calcoli la media.
13.3 Esercizio - Funzione Ricorsiva
Crea una funzione ricorsiva che calcoli la somma dei numeri da 1 a n.
13.4 Esercizio - Funzione Generatore
Scrivi un generatore che produca i numeri pari fino a un valore dato.
13.5 Esercizio - Funzioni e Liste
Scrivi una funzione chiamata “analizza_lista” che:
- riceva una lista di numeri interi
- restituisca:
- la somma degli elementi
- la media
- il valore massimo
- il valore minimo
Esempio:
numeri = [3, 7, 2, 9, 4]
risultato = analizza_lista(numeri)
print(risultato)
Output atteso: (25, 5.0, 9, 2)
13.6 Esercizio - Funzioni e Dizionario
Scrivi una funzione chiamata “statistiche_studenti” che:
-
riceva un dizionario nel formato:
studenti = { "Anna": 28, "Marco": 22, "Luca": 30, "Sara": 25 } -
restituisca:
- il nome dello studente con il voto più alto
- il nome dello studente con il voto più basso
- la media dei voti
Output di esempio: (“Luca”, “Marco”, 26.25)
13.7 Esercizio - Gestione avanzata con *args e **kwargs
Scrivi una funzione “crea_profilo” che:
- accetti:
- nome e cognome come parametri obbligatori
- un numero variabile di informazioni aggiuntive tramite
**kwargs
- restituisca un dizionario con tutte le informazioni
Esempio:
profilo = crea_profilo(
"Anna",
"Rossi",
eta=25,
citta="Roma",
hobby="pittura"
)
print(profilo)
13.8 Esercizio completo - Gioco del Tris (Tic-Tac-Toe)
Realizza il gioco del Tris usando le funzioni.
Requisiti minimi:
- Rappresenta la griglia di gioco come una lista di 9 elementi (3x3)
- Scrivi una funzione
stampa_griglia(griglia)che mostri il campo di gioco - Scrivi una funzione
mossa(griglia, posizione, simbolo)che:- controlli se la posizione è valida
- inserisca il simbolo (
XoO)
- Scrivi una funzione
controlla_vittoria(griglia, simbolo)che ritorniTruese il giocatore ha vinto - Alterna i turni tra due giocatori
- Termina la partita in caso di:
- vittoria
- pareggio Bonus:
- Gestione input errato
- Possibilità di rigiocare
- Contatore delle vittorie
- Versione contro il computer
Esempio di griglia:
X | O | X
---------
O | X |
---------
| O | X