6. Funzioni

6.1. Script [fonc_01]: ambito delle variabili
Lo script [fonc_01] mostra esempi di ambito delle variabili tra le funzioni:
Risultati
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_01.py
f1[i,j]=[1,10]
f2[i,j]=[2,20]
f3[i,j]=[1,30]
[i,j]=[2,0]
Process finished with exit code 0
Note:
- Lo script illustra l'uso della variabile i, dichiarata come globale nelle funzioni f1 e f2. In questo caso, il programma principale e le funzioni f1 e f2 condividono la stessa variabile i.
6.2. Script [fonc_02]: ambito delle variabili
Lo script [fonc_03] si basa sullo script [fonc_02] e mostra come evitare l'uso delle variabili globali:
Commenti:
- righe 2, 12: invece di essere dichiarata globale, la variabile [i] viene passata come parametro alle funzioni f1 e f2;
- righe 9, 19: le funzioni f1 e f2 restituiscono la variabile [i] modificata al programma principale. Il programma principale la recupera alle righe 36 e 37;
Risultati
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_02.py
f1[i,j]=[1,10]
f2[i,j]=[2,20]
f3[i,j]=[1,30]
[i,j]=[2,0]
Process finished with exit code 0
6.3. Script [fonc_03]: ambito delle variabili
Lo script [fonc_03] illustra una particolarità delle variabili utilizzate sia all'interno di una funzione che nel codice che la chiama, a seconda che la variabile sia utilizzata solo per la lettura all'interno della funzione o meno.
Note
- riga 34: il codice principale definisce una variabile [i];
- righe 1–5: anche la funzione f1 utilizza una variabile [i] senza assegnarle alcun valore. Si tratta di una lettura della variabile [i]. In questo caso, la variabile [i] utilizzata è quella proveniente dal codice chiamante, riga 34;
- righe 8–18: anche la funzione f2 utilizza una variabile [i], ma le assegna un valore alla riga 16. L'assegnazione di un valore alla variabile [i] in f2 rende automaticamente [i] una variabile locale della funzione [f2]. Questa funzione quindi “nasconde” la variabile [i] al codice chiamante;
- riga 14: l'operazione di scrittura sulla variabile locale [i] fallirà perché non ha alcun valore quando si raggiunge la riga 14. Essa ottiene il suo valore alla riga 16. Si verificherà un'eccezione. Per questo motivo, la riga 14 è stata inserita all'interno di un blocco try/catch;
- righe 21–29: la funzione f3 fa la stessa cosa della funzione f2 ma definisce la sua variabile locale [i] prima;
Risultati
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_03.py
[f1] i=10
[f1] j=20
[main] i=10, j=20
[f2] erreur=local variable 'i' referenced before assignment
[main] i=10
[f3] i=7
[main] i=10
Process finished with exit code 0
6.4. Script [fonc_04]: modalità di passaggio dei parametri
Lo script è il seguente:
Risultati
Note:
- In Python tutto è un oggetto. Alcuni oggetti sono detti "immutabili": non possono essere modificati. È il caso dei numeri, delle stringhe e delle tuple. Quando gli oggetti Python vengono passati come argomenti alle funzioni, sono i loro riferimenti ad essere passati, a meno che questi oggetti non siano "immutabili", nel qual caso è il valore dell'oggetto ad essere passato;
- Le funzioni f1 (riga 2) e f2 (riga 7) hanno lo scopo di illustrare il passaggio di un parametro di output. Vogliamo che il parametro effettivo di una funzione venga modificato dalla funzione;
- Righe 2–3: La funzione f1 modifica il suo parametro formale a. Vogliamo sapere se anche il parametro effettivo verrà modificato;
- righe 14–15: il parametro effettivo è x = 1. La riga 2 dei risultati mostra che il parametro effettivo non viene modificato. Pertanto, il parametro effettivo x e il parametro formale a sono due oggetti diversi;
- righe 8–10: la funzione f2 modifica i propri parametri formali a e b e li restituisce come risultati;
- righe 17–18: i parametri effettivi (x, y) vengono passati a f2 e il risultato di f2 viene assegnato a (x, y). La riga 3 dei risultati mostra che i parametri effettivi (x, y) sono stati modificati.
Concludiamo che quando gli oggetti "immutabili" sono parametri di output, devono far parte dei risultati restituiti dalla funzione.
6.5. Script [fonc_05]: Ordine delle funzioni in uno script
Lo script [fonc_05] mostra che una funzione non può essere chiamata se non è stata incontrata in precedenza nel codice:
Note
- La riga 2 causerà un errore perché utilizza la funzione f2, che non è stata ancora definita nello script;
Risultati
6.6. Script [fonc_06]: Ordine delle funzioni in uno script
Lo script [fonc_06] mostra che ciò che vale per il codice chiamante non vale per le funzioni:
Note
- riga 3: la funzione [f2] utilizza la funzione [f1] definita più avanti nello script. Tuttavia, ciò non causa un errore. Possiamo quindi concludere che l'ordine in cui le funzioni sono definite in uno script Python non ha importanza;
Risultati
6.7. Script [fonc_07]: Utilizzo dei moduli
Lo script [fonc_07] mostra come isolare le funzioni in un modulo.

Isoliamo le funzioni riutilizzabili in un modulo, anziché spostarle da uno script all'altro:
- le inseriamo in un file separato che dichiariamo in modo specifico;
- gli script che necessitano di queste funzioni "importano" il modulo che le contiene;
Lo script [fonctions_module_01] è il seguente:
Esistono diversi modi per garantire che le funzioni presenti nello script [fonctions_module_01] possano essere richiamate da altri script. Questi metodi variano a seconda che lo script venga eseguito all'interno di [PyCharm] o meno.
In [PyCharm], i moduli importati vengono cercati in cartelle specifiche denominate [Root Sources]. Esistono due modi per rendere una cartella una [Root Source]:

- in [4], la cartella ha cambiato colore;
Dopo questa operazione, la cartella [funzioni/moduli] viene riconosciuta come cartella sorgente. È quindi possibile scrivere in uno script:
Per importare/utilizzare la funzione f2 definita nel modulo [functions_module_01.py].
![]() |
Un altro metodo consiste nell'utilizzare le proprietà del progetto:
- sopra, la sequenza [1-6] consente di utilizzare la cartella [shared] come cartella in cui memorizzare i moduli da importare;
Per ora, non dichiareremo nessuna cartella come [Sources Root] diversa dalla radice del progetto:

Una volta fatto ciò, possiamo scrivere il seguente script [fonc-07]:
- Riga 2: importiamo l'oggetto [sys] in modo da poter utilizzare il suo attributo [path] alla riga 5, che fornisce il cosiddetto [Python Path]: un elenco di directory in cui verranno cercati i moduli importati;
- riga 6: importiamo la funzione f2 dal modulo [fonctions_module_01]. Per fare riferimento a questo modulo, utilizziamo il percorso che va dalla radice del progetto al modulo. Con PyCharm, la radice del progetto è sempre inclusa nelle cartelle cercate quando si cerca un modulo importato in uno script. Questa cartella fa quindi parte del [Python Path] del progetto. Questo è ciò che la riga 5 ci permetterà di verificare;
- Riga 6: se dovessimo descrivere il percorso dalla radice del progetto alla cartella [fonctions_module_01], scriveremmo [fonctions/shared/fonctions_module_01]. Nel percorso di un modulo, la barra / viene sostituita da un punto. Scriviamo quindi [fonctions.modules.fonctions_module_01];
- Dopo la riga 6, viene definita la funzione f2. La utilizziamo alla riga 8;
Risultati
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_07.py
Python path=['C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions\\shared', 'C:\\myprograms\\Python38\\python38.zip', 'C:\\myprograms\\Python38\\DLLs', 'C:\\myprograms\\Python38\\lib', 'C:\\myprograms\\Python38', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv\\lib\\site-packages']
310
Process finished with exit code 0
Sopra:
- evidenziato in verde, possiamo vedere che la radice del progetto fa parte del [Python Path];
- evidenziato in giallo, si può notare che anche la cartella contenente lo script eseguito fa parte del [Python Path];
- gli altri elementi del [Python Path] provengono direttamente dalla cartella di installazione di Python;
Cosa succede quando non usiamo PyCharm per eseguire [fonc-07]?


- in [1], eseguiamo lo script [fonc-07]. Ci troviamo nella cartella [functions];
- In [2], vediamo che la directory di esecuzione fa parte del [Python Path]. È sempre così. Possiamo anche vedere che la directory principale [C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020] non fa parte del [Python Path];
- in [3], l'interprete Python segnala che non riesce a trovare il modulo [fonctions];
Per trovare il modulo importato [fonctions.shared.fonctions_module_01], l'interprete Python cerca nelle cartelle del [Python Path] una sottocartella denominata [fonctions]. Non riesce a trovarla da nessuna parte. Questo perché la sottocartella [functions] si trova nella cartella [C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020], che non fa parte del [Python Path].
Lo script [fonc-08] fornisce una possibile soluzione a questo problema.
6.8. Script [fonc_08]: Aggiunta di cartelle al [Python Path]
È possibile modificare il [Python Path] a livello di programmazione, come mostrato nello script [fonc-08]:
Note
- riga 4: la variabile speciale [__file__] è il nome dello script in esecuzione. A seconda del contesto di esecuzione, questo nome può essere assoluto (PyCharm) o relativo (console). La funzione [os.path.abspath] restituisce il percorso assoluto del file il cui nome le viene passato. La funzione [os.path.dirname] restituisce il percorso assoluto della directory contenente il file il cui nome le viene passato;
- Riga 10: [sys.path] è una lista contenente i nomi delle directory da cercare quando si cerca un modulo. Aggiungiamo a questa lista la radice del progetto definita alla riga 4;
- visualizziamo il [Python Path] prima (riga 8) e dopo (riga 12) la modifica;
- riga 15: importiamo il modulo [fonctions_module_01], che contiene la funzione f2;
L'esecuzione in PyCharm produce i seguenti risultati:
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_08.py
Python path avant=['C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions\\shared', 'C:\\myprograms\\Python38\\python38.zip', 'C:\\myprograms\\Python38\\DLLs', 'C:\\myprograms\\Python38\\lib', 'C:\\myprograms\\Python38', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv\\lib\\site-packages']
Python path après=['C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions\\shared', 'C:\\myprograms\\Python38\\python38.zip', 'C:\\myprograms\\Python38\\DLLs', 'C:\\myprograms\\Python38\\lib', 'C:\\myprograms\\Python38', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv\\lib\\site-packages', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions/shared']
310
Process finished with exit code 0
- riga 3: vediamo che la cartella [shared] compare due volte nel [Python Path]. Possiamo evitarlo, ma in questo caso non causa alcun problema;
- riga 4: la funzione f2 è stata eseguita con successo;
Ora eseguiamo [fonc-08] in un terminale:
(venv) C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\fonctions>python fonc_08.py
Python path avant=['C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions', 'C:\\myprograms\\Python38\\python38.zip', 'C:\\myprograms\\Python38\\DLLs', 'C:\\myprograms\\Python38\\lib', 'C:\\myprograms\\Python38', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv\\lib\\site-packages']
Python path après=['C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions', 'C:\\myprograms\\Python38\\python38.zip', 'C:\\myprograms\\Python38\\DLLs', 'C:\\myprograms\\Python38\\lib', 'C:\\myprograms\\Python38', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv\\lib\\site-packages', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions/shared']
310
- riga 2: come prima, la cartella [shared] non è nel [Python Path];
- riga 3: ora lo è;
- riga 4: la funzione f2 è stata trovata;
6.9. Script [fonc_09]: dichiarazione dei tipi dei parametri
Lo script [fonc_09] mostra che è possibile dichiarare il tipo dei parametri di una funzione così come quello del risultato. Tuttavia, questa dichiarazione è utile solo per documentare la funzione. L'interprete Python non verifica se i parametri effettivi della funzione sono del tipo previsto. Tuttavia, PyCharm segnala le incongruenze di tipo tra i parametri effettivi e quelli formali. Questo motivo da solo rende indispensabili le dichiarazioni di tipo.
Lo script è il seguente:
Note:
- Riga 5: dichiariamo che il parametro formale [param] è di tipo [int] e che anche il tipo di ritorno della funzione è [int];
- riga 11: il parametro effettivo della funzione [show] è del tipo corretto;
- riga 12: il parametro effettivo della funzione [show] non è del tipo corretto;
Risultati
- riga 10: il tipo del parametro [param] è [str]. Quando appare questo messaggio, abbiamo già inserito il codice della funzione [show]. L'interprete Python ha quindi accettato che il parametro effettivo della funzione [show] sia di tipo [str];
- La riga 7 del codice genera l'eccezione mostrata nelle righe 4–10 dei risultati;
PyCharm indica comunque che c'è un problema:

In [1], PyCharm ha evidenziato la chiamata errata.
6.10. Script [fonc_10]: parametri denominati
Per passare parametri a una funzione, è possibile utilizzare i nomi dei suoi parametri formali. In questo caso, non è necessario seguire l'ordine dei parametri formali:
Note
- riga 2: la funzione f ha due parametri formali, x e y;
- riga 7: quando si chiama la funzione f, è possibile utilizzare i nomi dei parametri formali. Questa pratica può essere utile in almeno due casi:
- la funzione ha molti parametri, la maggior parte dei quali ha valori predefiniti. Quando si chiama la funzione, la tecnica sopra descritta consente di inizializzare solo quei parametri per i quali non si desidera utilizzare il valore predefinito;
- se i parametri formali hanno nomi significativi, l'uso di parametri con nome nella chiamata alla funzione migliora la leggibilità del codice;
Risultati
6.11. Script [fonc_11]: funzione ricorsiva
Lo script [fonc_11] è un esempio di funzione ricorsiva (che richiama se stessa):
Commenti
- righe 1-9: la funzione fattoriale;
- riga 9: la funzione [factorial] chiama se stessa;
- righe 5-6: una funzione ricorsiva deve sempre terminare quando viene soddisfatta una condizione; altrimenti, si ha una ricorsione infinita;
Risultati
6.12. Script [fonc_12]: funzione ricorsiva
La funzione [fonc_12] fornisce ulteriori dettagli sul funzionamento della ricorsione:
Commenti
- riga 5: ci stiamo ancora concentrando sulla funzione fattoriale. Aggiungiamo il parametro [j];
- riga 12: la variabile j viene incrementata regolarmente ad ogni calcolo del fattoriale. Visualizziamo il suo valore prima (riga 12) e dopo (riga 16) la ricorsione (riga 15);
Risultati
- righe 2–8: vediamo che il valore di [j] aumenta finché la ricorsione continua, fino a quando non soddisfa la condizione in cui la ricorsione si interrompe. Da quel momento in poi, il ritorno dalle chiamate alla funzione [fact] avviene nell'ordine inverso delle chiamate;
- righe 10–16: queste visualizzazioni riflettono i successivi ritorni dalla chiamata al fattoriale. La variabile [j] torna al suo valore iniziale di 1;
