Corso

Le funzioni sono una parte essenziale del linguaggio di programmazione Python: potresti aver già incontrato e usato alcune delle tante funzioni fantastiche incluse nel linguaggio o fornite dall’ecosistema di librerie. Tuttavia, come data scientist, avrai continuamente bisogno di scrivere funzioni tue per risolvere i problemi che i tuoi dati ti pongono.
Questo tutorial utilizza la sintassi di Python 3. Tutti gli esempi funzionano su Python 3.10+ e sono stati aggiornati per riflettere le convenzioni moderne (f-string, type hint, parametri solo posizionali e solo keyword). L’attuale release stabile è Python 3.14.
Per eseguire facilmente in autonomia tutto il codice di esempio di questo tutorial, puoi creare gratuitamente un workbook DataLab con Python preinstallato e tutti gli esempi inclusi. Per fare più pratica sulla scrittura di funzioni Python, dai un’occhiata a questo esercizio pratico di DataCamp o prova il nostro corso Python Data Science Toolbox!
Funzioni in Python
In programmazione usi le funzioni per raggruppare un insieme di istruzioni che vuoi riutilizzare più volte o che, per complessità, è meglio incapsulare in un sottoprogramma e chiamare quando serve. In altre parole, una funzione è un blocco di codice scritto per eseguire un compito specifico. Per svolgere quel compito, la funzione può richiedere uno o più input, oppure nessuno. Al termine, può restituire uno o più valori, oppure nessuno.
In Python esistono tre tipi di funzioni:
-
Funzioni built-in, come
help()per chiedere aiuto,min()per ottenere il valore minimo,print()per stampare un oggetto nel terminale… Trovi una panoramica di altre funzioni qui. -
Funzioni definite dall’utente (UDF), cioè funzioni che gli utenti creano per semplificarsi il lavoro; e
-
Funzioni anonime, chiamate anche funzioni lambda perché non sono dichiarate con la parola chiave standard
def.
Funzioni vs. metodi
Un metodo è una funzione che fa parte di una classe. Vi accedi tramite un’istanza o un oggetto della classe. Una funzione non ha questa restrizione: è semplicemente una funzione autonoma. Questo significa che tutti i metodi sono funzioni, ma non tutte le funzioni sono metodi.
Considera questo esempio, in cui prima definisci una funzione plus() e poi una classe Summation con un metodo sum():
Se ora vuoi chiamare il metodo sum() che fa parte della classe Summation, devi prima definire un’istanza o un oggetto di quella classe. Quindi, definiamo un oggetto del genere:
Ricorda che questa istanziazione non è necessaria quando vuoi chiamare la funzione plus()! Potresti eseguire plus(1,2) nel riquadro di DataCamp Light senza alcun problema!
Parametri vs. argomenti
I parametri sono i nomi usati quando si definisce una funzione o un metodo, ai quali verranno associati gli argomenti. In altre parole, gli argomenti sono i valori che passi a una chiamata di funzione o metodo, mentre il codice della funzione o del metodo si riferisce a questi valori tramite i nomi dei parametri.
Considera il seguente esempio e riguardati il riquadro DataCamp Light qui sopra: passi due argomenti al metodo sum() della classe Summation, anche se in precedenza avevi definito tre parametri, cioè self, a e b.
Che fine ha fatto self?
Il primo argomento di ogni metodo di classe è sempre un riferimento all’istanza corrente della classe, che in questo caso è Summation. Per convenzione, questo argomento si chiama self.
Tutto ciò significa che in questo caso non passi esplicitamente il riferimento a self perché self è il nome del parametro per un argomento passato implicitamente che si riferisce all’istanza attraverso cui viene invocato un metodo. Viene inserito implicitamente nella lista degli argomenti.
Come definire una funzione: funzioni definite dall’utente (UDF)
I quattro passaggi per definire una funzione in Python sono i seguenti:
-
Usa la parola chiave
defper dichiarare la funzione e seguila con il nome della funzione. -
Aggiungi i parametri alla funzione: devono essere tra parentesi tonde. Termina la riga con i due punti.
-
Aggiungi le istruzioni che la funzione deve eseguire.
-
Termina la funzione con un’istruzione return se deve restituire qualcosa. Senza return, la funzione restituirà l’oggetto
None.
Ovviamente, le tue funzioni diventeranno più complesse man mano che procedi: puoi aggiungere cicli for, controllo di flusso, … e altro ancora per renderle più fini:
def hello():
name = input("Enter your name: ")
if name:
print(f"Hello {name}")
else:
print("Hello World")
hello()
Nella funzione qui sopra, chiedi all’utente di inserire un nome. Se non viene fornito alcun nome, la funzione stamperà "Hello World". Altrimenti, l’utente otterrà un saluto personalizzato.
Ricorda anche che puoi definire uno o più parametri per la tua UDF. Ne saprai di più nella sezione Argomenti della funzione. Inoltre, puoi restituire uno o più valori come risultato della funzione, oppure nessuno.
L’istruzione return
Nota che, dato che stai stampando qualcosa nella tua UDF hello(), non hai realmente bisogno di restituirla. Non ci sarà alcuna differenza tra la funzione sopra e questa:
Tuttavia, se vuoi continuare a lavorare con il risultato della tua funzione e provare alcune operazioni su di esso, dovrai usare l’istruzione return per restituire effettivamente un valore, come una stringa, un intero, …. Considera il seguente scenario, in cui hello() restituisce la stringa "hello", mentre la funzione hello_noreturn() restituisce None:
La seconda funzione genera un errore perché non puoi eseguire operazioni con un None. Otterrai un TypeError che indica che non puoi effettuare l’operazione di moltiplicazione tra NoneType (il None risultato di hello_noreturn()) e int (2).
Consiglio: le funzioni escono immediatamente quando incontrano un’istruzione return, anche se ciò significa che non restituiranno alcun valore:
Un’altra cosa che vale la pena menzionare quando lavori con return è che puoi usarla per restituire più valori. Per farlo, usi le tuple.
Ricorda che questa struttura dati è molto simile a una lista: può contenere più valori. Tuttavia, le tuple sono immutabili, il che significa che non puoi modificare gli elementi memorizzati al loro interno! Le costruisci con l’aiuto delle parentesi tonde (). Puoi “spacchettare” le tuple in più variabili usando la virgola e l’operatore di assegnazione.
Dai un’occhiata al seguente esempio per capire come la tua funzione può restituire più valori:
Nota che l’istruzione return return sum, a avrebbe lo stesso risultato di return (sum, a): in realtà la prima racchiude sum e a in una tupla “dietro le quinte”!
Come chiamare una funzione
Nelle sezioni precedenti hai già visto molti esempi di come chiamare una funzione. Chiamare una funzione significa eseguire la funzione che hai definito, direttamente dal prompt di Python o attraverso un’altra funzione (come vedrai nella sezione “Funzioni annidate”).
Chiama la tua nuova funzione hello() semplicemente eseguendo hello(), proprio come nel riquadro DataCamp Light qui sotto:
Come aggiungere docstring a una funzione Python
Un altro aspetto essenziale nella scrittura di funzioni in Python: le docstring. Le docstring descrivono cosa fa la funzione, ad esempio i calcoli che esegue o i valori che restituisce. Queste descrizioni fungono da documentazione della funzione così che chiunque legga la docstring capisca cosa fa, senza dover seguire tutto il codice della definizione.
Le docstring delle funzioni si inseriscono subito dopo l’intestazione della funzione e sono racchiuse tra triple virgolette. Una docstring appropriata per la tua funzione hello() è ‘Stampa “Hello World”’.
def hello() -> None:
"""Prints "Hello World"."""
print("Hello World")
Nota che le docstring possono essere più estese dell’esempio riportato qui. Se vuoi approfondire le docstring, ti conviene dare un’occhiata ad alcuni repository Github di librerie Python come scikit-learn o pandas, dove troverai molti esempi!
Type hint
Strettamente correlate alle docstring — e quasi altrettanto comuni nel Python moderno — ci sono le type hint. Dalla versione 3.5 puoi annotare i parametri e il valore di ritorno della funzione con i tipi attesi. Ecco l’esempio più semplice possibile:
def plus(a: int, b: int) -> int:
return a + b
Il : int dopo ciascun parametro significa “questo dovrebbe essere un intero”, e il -> int dopo le parentesi indica “questa funzione restituisce un intero”. Python non applica queste annotazioni a runtime — puoi comunque passare una stringa a plus() e Python non si lamenterà finché qualcosa non si rompe. Ma strumenti come mypy, pyright e i type checker integrati in editor come VS Code e PyCharm usano questi hint per intercettare bug prima ancora di eseguire il codice.
Per tipi più complessi, puoi usare direttamente i generics built-in (Python 3.9+) o importare dal modulo typing:
def greet(names: list[str]) -> None:
for name in names:
print(f"Hello {name}")
def find_user(user_id: int) -> dict | None:
# returns the user dict, or None if not found
...
Argomenti di funzione in Python
In precedenza hai imparato la differenza tra parametri e argomenti. In breve, gli argomenti sono i valori che vengono passati a una chiamata di funzione o metodo, mentre il codice della funzione o del metodo fa riferimento a tali valori tramite i nomi dei parametri. Esistono quattro tipi di argomenti che le UDF in Python possono accettare:
- Argomenti predefiniti
- Argomenti obbligatori
- Argomenti keyword
- Numero variabile di argomenti
Argomenti predefiniti
Gli argomenti predefiniti assumono un valore di default se non viene passato alcun valore durante la chiamata della funzione. Puoi assegnare questo valore predefinito con l’operatore di assegnazione =, proprio come nel seguente esempio:
Argomenti obbligatori
Come lascia intendere il nome, gli argomenti obbligatori di una UDF sono quelli che devono esserci. Questi argomenti vanno passati durante la chiamata della funzione e nell’ordine esatto, proprio come nel seguente esempio:
Ti servono argomenti che corrispondano ai parametri a e b per chiamare la funzione senza errori. Se inverti a e b, il risultato non cambierà, ma potrebbe farlo se modifichi plus() come segue:
Argomenti keyword
Se vuoi assicurarti di chiamare tutti i parametri nell’ordine corretto, puoi usare gli argomenti keyword nella chiamata della funzione. Li usi per identificare gli argomenti tramite il nome del parametro. Riprendiamo l’esempio precedente per chiarire meglio:
Nota che usando gli argomenti keyword puoi anche invertire l’ordine dei parametri e ottenere comunque lo stesso risultato quando esegui la funzione:
Numero variabile di argomenti
Nei casi in cui non conosci il numero esatto di argomenti da passare a una funzione, puoi usare la seguente sintassi con *args:
L’asterisco (*) è posto prima del nome della variabile che contiene i valori di tutti gli argomenti variabili non keyword. Nota che avresti potuto passare anche *varint, *var_int_args o qualsiasi altro nome alla funzione plus().
Consiglio: prova a sostituire *args con un altro nome che includa l’asterisco. Vedrai che il codice sopra continua a funzionare!
Vedi che la funzione qui sopra usa la funzione built-in di Python sum() per sommare tutti gli argomenti passati a plus().
Variabili globali vs. locali
In generale, le variabili definite all’interno del corpo di una funzione hanno ambito locale, mentre quelle definite all’esterno hanno ambito globale. Questo significa che le variabili locali sono definite all’interno di un blocco funzione e sono accessibili solo dentro quella funzione, mentre le variabili globali possono essere accessibili da tutte le funzioni presenti nello script:
Vedrai che otterrai un NameError che dice che name 'total' is not defined quando provi a stampare la variabile locale total definita all’interno del corpo della funzione. La variabile init, invece, può essere stampata senza problemi.
Parametri solo posizionali e solo keyword
Da Python 3.8 puoi avere un controllo maggiore su come gli argomenti devono essere passati usando due marcatori speciali nella firma della funzione: / e *. Tutto ciò che si trova prima di / può essere passato solo positionalmente; tutto ciò che si trova dopo * può essere passato solo come keyword.
def greet(name, /, greeting="Hello", *, punctuation="!"):
print(f"{greeting} {name}{punctuation}")
Ecco come si comporta lato chiamata:
greet("Alice") # works
greet("Alice", greeting="Hi") # works
greet("Alice", "Hi", punctuation="?") # works
greet(name="Alice") # TypeError: name is positional-only
greet("Alice", "Hi", "?") # TypeError: punctuation is keyword-only
Perché potresti volerlo? Due motivi principali.
Primo, i parametri solo posizionali ti permettono di rinominarli in seguito senza rompere il codice di nessuno — dato che a nessuno è consentito usare il nome del parametro come keyword, sei libero di cambiarlo.
Secondo, i parametri solo keyword obbligano chi chiama a essere esplicito su ciò che sta passando, il che rende le chiamate più leggibili quando hai diverse opzioni o impostazioni facoltative.
In breve, sono un modo pulito per imporre l’intento.
Funzioni anonime in Python
Le funzioni anonime in Python sono chiamate anche funzioni lambda perché invece di dichiararle con la parola chiave standard def, usi la parola chiave lambda.
Nel riquadro DataCamp Light qui sopra, lambda x: x*2 è la funzione anonima o lambda. x è l’argomento e x*2 è l’espressione o istruzione che viene valutata e restituita. La particolarità di questa funzione è che non ha nome, a differenza degli esempi visti nella prima parte di questo tutorial sulle funzioni. Se dovessi scrivere la funzione sopra come UDF, il risultato sarebbe il seguente:
def double(x):
return x*2
Consideriamo un altro esempio di funzione lambda in cui lavori con due argomenti:
Usi funzioni anonime quando ti serve una funzione senza nome per un breve periodo, creata a runtime. Contesti specifici in cui questo è utile sono quando lavori con filter(), map() e reduce():
La funzione filter() filtra, come suggerisce il nome, la lista di input originale my_list in base al criterio >10. Con map(), invece, applichi una funzione a tutti gli elementi della lista my_list. In questo caso, moltiplichi tutti gli elementi per 2.
Nota che la funzione reduce() fa parte della libreria functools. Usi questa funzione in modo cumulativo sugli elementi della lista my_list, da sinistra a destra, e riduci la sequenza a un singolo valore, in questo caso 55.
Usare main() come funzione in Python
Se hai esperienza con altri linguaggi di programmazione come Java, saprai che la funzione main è necessaria per eseguire le funzioni. Come hai visto negli esempi sopra, questo non è necessariamente richiesto in Python. Tuttavia, includere una funzione main() nel tuo programma Python può essere utile per strutturare logicamente il codice: tutti i componenti più importanti sono contenuti all’interno di questa funzione main().
Puoi definire facilmente una funzione main() e chiamarla proprio come hai fatto con tutte le altre funzioni sopra:
Tuttavia, così com’è ora, il codice della tua funzione main() verrà eseguito quando la importi come modulo. Per assicurarti che ciò non accada, chiama la funzione main() quando __name__ == '__main__'.
Questo significa che il codice del riquadro qui sopra diventa:
Nota che oltre alla funzione __main__, esiste anche __init__ che inizializza un’istanza di una classe o un oggetto. In parole povere, agisce come costruttore o inizializzatore ed è chiamata automaticamente quando crei una nuova istanza di una classe. Con quella funzione, il nuovo oggetto creato viene assegnato al parametro self, che hai visto prima in questo tutorial. Guarda il seguente esempio:
class Dog:
"""A simple Dog class.
Args:
legs: Number of legs so that the dog can walk.
color: The color of the fur.
"""
def __init__(self, legs: int, color: str) -> None:
self.legs = legs
self.color = color
def bark(self) -> str:
return "bark" * 2
if __name__ == "__main__":
dog = Dog(4, "brown")
print(dog.bark())
Continua a fare pratica con le funzioni in Python
Complimenti! Hai completato questo breve tutorial sulle funzioni in Python. Se vuoi ripassare altri argomenti base della programmazione in Python, non perdere il corso Data Types for Data Science, dove consoliderai e metterai in pratica le tue conoscenze su liste, dizionari, tuple, set e date e orari.
Domande frequenti sulle funzioni in Python
Cos’è una funzione in Python?
Una funzione è un blocco di codice riutilizzabile che esegue un compito specifico. Può accettare input, elaborarli e restituire output.
Come si definisce una funzione in Python?
Per definire una funzione in Python, usa la parola chiave def, dai un nome alla funzione, aggiungi eventuali parametri tra parentesi, scrivi il codice e opzionalmente return un valore.
Qual è la differenza tra funzioni e metodi in Python?
Le funzioni sono autonome, mentre i metodi appartengono alle classi. Tutti i metodi sono funzioni, ma non tutte le funzioni sono metodi.
Quali sono i tipi di funzioni in Python?
Python ha funzioni built-in (come print()), funzioni definite dall’utente (le tue creazioni personalizzate) e funzioni anonime (le lambda di breve durata).
Qual è la differenza tra parametri e argomenti?
I parametri sono segnaposto nella definizione della funzione, mentre gli argomenti sono i valori reali che passi quando la chiami.
Cos’è una funzione lambda?
Una funzione lambda è una funzione senza nome, scritta in una sola riga, per compiti rapidi.
Perché usare la funzione __main__?
La funzione __main__ mantiene il codice organizzato e fa sì che parti specifiche vengano eseguite solo quando lo script è lanciato direttamente, non quando è importato.
Qual è la differenza tra variabili globali e locali?
Le variabili globali funzionano ovunque, mentre quelle locali esistono solo all’interno della loro funzione.

