Funzioni
E' possibile definire le funzioni come degli insiemi composti da una o più istruzioni necessarie per lo svolgimento di un determinato compito; uno dei vantaggi derivanti dall'utilizzo di questi costrutti riguarda il fatto che essi possono essere definiti una volta sola e poi utilizzati in più di un'occasione all'interno della medesima applicazione, ciò avverrà tramite un meccanismo denominato "chiamata alla funzione".
In questo modo si eviteranno inutili ripetizioni di codice con un evidente risparmio di tempo in sede di sviluppo, a cui si accompagna la possibilità di creare sorgenti più snelli, leggibili e performanti.
Python prevede sia funzioni integrate (ad esempio, le funzioni
print()
e input()
) che la possibilità di creare funzioni personalizzate; in questo capitolo verranno analizzate le seconde, delle prime ci occuperemo in una successiva sezione.
Definire una funzione
Si può definire una funzione adoperando la seguente, generica, sintassi:
def nome_funzione(parametri):
"""docstring"""
blocco function
In particolare, la definizione di una funzione ha le seguenti componenti:
- la parola chiave
def
, che contrassegna l'inizio dell'intestazione della funzione; - un nome di funzione che la identifichi in modo univoco;
- parametri o argomenti (opzionali) attraverso i quali passiamo valori alla funzione;
- due punti
:
per contrassegnare la fine dell'intestazione della funzione; - stringa di documentazione facoltativa, detta
docstring
, per descrivere cosa fa la funzione; - un blocco di codice che contiene le istruzioni che saranno eseguite dalla funzione;
- un'istruzione di
return
(opzionale e che vedremo in seguito) che consente alla funzione di restituire un valore.
nome_funzione(eventuali_parametri)
Docstring
La prima stringa dopo l'intestazione della funzione è chiamata
Sebbene facoltativa, l'inserimento di una
docstring
ed è l'abbreviazione di documentation string. Tale stringa è utilizzata per spiegare, in breve, quello che fa la funzione.Sebbene facoltativa, l'inserimento di una
docstring
è una buona pratica di programmazione, che consente allo sviluppatore e agli utilizzatori del programma di comprendere meglio la logica della funzione. Si consideri, a titolo di esempio, il seguente codice:
def lavori_in_corso():
"""
In questa funzione implementeremo una delle
richieste del nostro cliente, per il momento
non ancora nota.
"""
pass
print(lavori_in_corso.__doc__)
Ebbene, in questo esempio stiamo supponendo che il nostro cliente voglia sviluppare una certa funzione, non ancora nota, che codificheremo in seguito (da qui l'utilizzo della già nota keyword
pass
). Eseguendo lo script, otterremo il seguente messaggio, contenente la descrizione della funzione:
In questa funzione implementeremo una delle
richieste del nostro cliente, per il momento
non ancora nota.
Arguments
Come preannunciato, possiamo passare dei parametri di input alle funzioni. Questi ultimi svolgono sostanzialmente la funzione di placeholders (segnalibri), comunicando all'applicazione il numero di argomenti che dovranno essere passati alla funzione; questi ultimi potranno essere valorizzati arbitrariamente dallo sviluppatore sulla base delle proprie esigenze.
A questo proposito, la funzione presentata nell'esempio seguente ha il compito di concatenare tre parametri (
nome
, cognome
e msg
) restituendoli in output all'interno di un stringa:
def saluto(nome, cognome, msg):
"""
La funzione genera stampa sul prompt
una stringa prodotta dalla concatenazione
dei valori dei parametri passati ad essa.
"""
print("Salve, " + nome + " " + cognome + ". " + msg)
# chiamata alla funzione
saluto("Franco", "Rossi", "Come stai?")
Il risultato dell'esecuzione del codice proposto e della chiamata alla funzione
saluto
sarà il seguente:
Salve, Franco Rossi. Come stai?
Default arguments
Python consente anche la definizione di parametri di default attraverso l'operatore di assegnamento
=
. Qui un esempio in cui al parametro msg
viene assegnato il valore di default "Come stai?"
:
def saluto(nome, cognome, msg = "Come stai?"):
"""
La funzione genera stampa sul prompt
una stringa prodotta dalla concatenazione
dei valori dei parametri passati ad essa.
"""
print("Salve, " + nome + " " + cognome + ". " + msg)
# chiamata alla funzione
saluto("Franco", "Rossi")
saluto("Andrea", "Bianchi", "Erano settimane che non ci incontravamo.")
Il relativo output sarà:
Salve, Franco Rossi. Come stai?
Salve, Andrea Bianchi. Erano settimane che non ci incontravamo.
Si noti che, quando nella chiamata alla funzione non viene specificato il parametro
A livello di sintassi, il linguaggio Python non consente di definire i parametri di default prima di quelli non di default. Infatti, l'intestazione:
msg
, allora quest'ultimo assume il suo valore di default.A livello di sintassi, il linguaggio Python non consente di definire i parametri di default prima di quelli non di default. Infatti, l'intestazione:
def saluto(msg = "Come stai?", nome, cognome):
produrrà il seguente errore:
SyntaxError: non-default argument follows default argument
Keyword arguments
Quando chiamiamo una funzione con alcuni valori, questi valori vengono assegnati agli argomenti in base alla loro posizione.
Ad esempio, riferendoci alla funzione saluto()
, durante la chiamata saluto("Andrea", "Bianchi", "Come stai?")
, il valore Andrea
viene assegnato al parametro nome
, Bianchi
al parametro cognome
, e infine Come stai?
al parametro msg
.
Python consente di chiamare le funzioni usando anche le keyword dei parametri. Quando chiamiamo le funzioni in questo modo, l'ordine dei parametri può essere modificato. Le chiamate successive sono infatti tutte valide, e producono lo stesso risultato.
saluto(nome = "Andrea", cognome = "Bianchi", msg = "Come stai?")
saluto(cognome = "Bianchi", nome = "Andrea", msg = "Come stai?")
saluto(msg = "Come stai?", cognome = "Bianchi", nome = "Andrea")
Occorre tuttavia evitare di mixare i due metodi, cioè assegnare alcuni valori tramite posizione, e altri tramite keyword. Infatti, la chiamata:
saluto(nome = "Andrea", "Bianchi", "Come stai?")
produrrà l'errore:
SyntaxError: non-keyword arg after keyword arg
Arbitrary arguments
A volte, non conosciamo in anticipo il numero di argomenti che saranno passati in una funzione. Tuttavia, Python ci permette di gestire questo tipo di situazione attraverso chiamate di funzioni con un numero arbitrario di argomenti.
In tal caso, nella definizione della funzione, basterà utilizzare l'asterisco
*
prima del nome per indicare un parametro composto da un numero indefinito di argomenti. Ecco un esempio.
def ciao(*args):
"""
Questa funzione saluta tutte le persone contenute
nella tupla args.
"""
for arg in args:
print("Ciao ", arg)
ciao("Monica","Grazia","Luigi","Giovanni")
Il relativo output sarà:
Ciao Monica
Ciao Grazia
Ciao Luigi
Ciao Giovanni
Analogamente, può capitare di dover passare alla funzione un numero indefinito di keyword arguments. In tal caso, si potrà ricorrere al doppio asterisco
**
prima del nome per indicare un parametro composto da un numero indefinito di keyword arguments. Qui un esempio:
def portate(**kwargs):
"""
Questa funzione elenca le portate
previste nel menu.
"""
for key in kwargs:
value = kwargs[key]
print(key + ": " + value)
portate(antipasto = "mozzarelle", primo = "carbonara", secondo = "bistecca", dolce = "budino")
L'output prodotto sarà:
antipasto: mozzarelle
primo: carbonara
secondo: bistecca
dolce: budino
Return
Esistono anche funzioni che restituiscono dei valori. In tal caso, il valore restituito seguirà l'istruzione
return
, la quale chiude di fatto il blocco della funzione stessa. Qualora l'istruzione return
sia assente, il valore restituito sarà invece uguale a None
. Qui di seguito proponiamo una funzione che restituisce il valore assoluto di un numero:
def valore_assoluto(num):
"""
Questa funzione restituisce il valore assoluto
del numero inserito in ingresso.
"""
if num >= 0:
return num
else:
return -num
# Output: 2
print(valore_assoluto(2))
# Output: 4
print(valore_assoluto(-4))
Scope e ciclo di vita
Lo scope (o visibilità) di una variabile è la parte di un programma in cui la variabile è riconosciuta. I parametri e le variabili definiti all'interno di una funzione non sono visibili dall'esterno. Quindi, hanno uno scope locale.
Il ciclo di vita di una variabile è invece il periodo attraverso il quale la variabile viene inserita e poi cancellata dalla memoria. Il ciclo di vita delle variabili all'interno di una funzione è pari al tempo necessario all'esecuzione della funzione stessa. Tali variabili sono distrutte una volta che la funzione termina, ragion per cui una funzione non ricorda i valori assunti dalle sue variabili locali nelle chiamate precedenti. Ecco un esempio per illustrare lo scope e il ciclo di vita di una variabile all'interno di una funzione.
Il ciclo di vita di una variabile è invece il periodo attraverso il quale la variabile viene inserita e poi cancellata dalla memoria. Il ciclo di vita delle variabili all'interno di una funzione è pari al tempo necessario all'esecuzione della funzione stessa. Tali variabili sono distrutte una volta che la funzione termina, ragion per cui una funzione non ricorda i valori assunti dalle sue variabili locali nelle chiamate precedenti. Ecco un esempio per illustrare lo scope e il ciclo di vita di una variabile all'interno di una funzione.
def my_func():
x = 10
print("Il valore di x nella funzione è: ", x)
x = 20
my_func()
print("Il valore di x fuori dalla funzione è: ", x)
L'output del programma sarà:
Il valore di x nella funzione è: 10
Il valore di x fuori dalla funzione è: 20
Possiamo vedere che il valore di
x
è inizialmente 20
. Anche se la funzione my_func()
ha cambiato il valore di x
a 10
, non ha influenzato il suo valore al di fuori della funzione.
Questo perché la variabile x
all'interno della funzione è diversa da quella all'esterno. Sebbene abbiano lo stesso nome, sono due variabili differenti con scope differenti.
D'altra parte, le variabili esterne alla funzione sono visibili dall'interno, vale a dire che hanno uno scope globale.
Possiamo leggere questi valori dall'interno della funzione ma, badate bene, non possiamo modificarli. Affinché una funzione sia in grado di modificare il valore delle variabili al di fuori di essa, tali variabili devono essere dichiarate come globali utilizzando la parola chiave global
. Infatti, eseguendo lo script:
def my_func():
global x
x = 10
print("Il valore di x nella funzione è: ", x)
x = 20
my_func()
print("Il valore di x fuori dalla funzione è: ", x)
otterremo l'ouput:
Il valore di x nella funzione è: 10
Il valore di x fuori dalla funzione è: 10