Comprendere l’uso di `if __name__ == ‘__main__’` in Python
In questa guida esploreremo in dettaglio la funzione e il significato dell’istruzione `if __name__ == ‘__main__’` in Python.
Ti sei mai imbattuto, esplorando un codice Python con diversi moduli, in questa particolare condizione? Se sì, nei prossimi paragrafi sveleremo il suo scopo e analizzeremo come può esserci utile.
Iniziamo subito!
Qual è il ruolo di `__name__` in Python?
In Python, un modulo è semplicemente un file con estensione `.py` che racchiude definizioni di funzioni, una serie di espressioni da valutare e altro ancora. Per esempio, se abbiamo un file denominato `hello_world.py`, lo chiameremo modulo o file `hello_world.py`.
Quando avvii un modulo Python, l’interprete Python assegna valori predefiniti a specifiche variabili prima di iniziare l’esecuzione: `__name__` è una di queste. La chiave per comprendere appieno il significato di `__name__` sta nel capire come funzionano le importazioni in Python.
📁 Scarica il codice di questa sezione qui.
Entra nella cartella `esempio-1`. Qui troverai il file `module1.py`. La variabile `__name__` risiede nello spazio dei nomi del modulo corrente.
Questo modulo stampa una riga di testo seguita dal valore della variabile `__name__`.
# example-1/module1.py print("Questo è module1.") print(f"La variabile __name__ di module1 è: {__name__}.")
Ora, eseguiamo `module1` dalla riga di comando.
$ python module1.py
Come si può vedere nell’output, la variabile `__name__` è impostata su `__main__`.
Questo è module1. La variabile __name__ di module1 è: __main__.
Importare moduli in Python
Oltre ad avviare un modulo Python, a volte può esserci utile sfruttare le funzionalità di un altro modulo Python all’interno del modulo attuale. Python semplifica questa operazione tramite le importazioni.
Le importazioni consentono di riutilizzare le funzioni di un altro modulo, importandolo nel contesto del modulo corrente, senza dover riscrivere il codice.
Il file `module2.py` contiene quanto segue. Abbiamo importato `module1` al suo interno.
# example-1/module2.py import module1 # module1 viene importato print(f"Questo è module2") print(f"La variabile __name__ di module2 è: {__name__}.")
Eseguiamo `module2.py` e osserviamo l’output.
$ python module2.py
Nell’output seguente:
- Notiamo che `module1` viene eseguito implicitamente quando lo importiamo in `module2` e l’output corrispondente viene stampato.
- Tuttavia, questa volta, la variabile `__name__` non è `__main__`, ma `module1`.
- Poiché abbiamo eseguito direttamente `module2`, la variabile `__name__` relativa a questo modulo è ora `__main__`.
Output Questo è module1. La variabile __name__ di module1 è: module1. Questo è module2 La variabile __name__ di module2 è: __main__.
💡 Concetto chiave:
– Se un modulo viene eseguito direttamente, la sua variabile `__name__` viene impostata su `__main__`.
– Se un modulo viene importato in un altro modulo, il suo valore di `__name__` assume il nome del modulo.
Esempio pratico di `if __name__ == ‘__main__’` in Python
In questa sezione, vedremo un esempio di utilizzo pratico dell’istruzione `if __name__ == ‘__main__’`. Definiremo una semplice funzione e quindi scriveremo dei test unitari per verificare il suo funzionamento.
📁 Scarica il codice e segui la guida.
Il codice per questa sezione si trova nella cartella `esempio-2`.
Qui, `add.py` è un file Python che contiene la definizione della funzione `add_ab()`. Questa funzione accetta due numeri come input e restituisce la loro somma.
# example-2/add.py def add_ab(a,b): return a + b
Utilizzeremo il modulo `unittest` di Python per testare la funzione `add_ab()`.
Scrivere casi di test per una funzione Python
Osserva il codice sottostante, che mostra il contenuto del modulo `test_add`.
# example-2/test_add.py import unittest from add import add_ab class TestAdd(unittest.TestCase): def test_add_23(self): self.assertEqual(add_ab(2,3), 5) def test_add_19(self): self.assertEqual(add_ab(1,9), 10) def test_add_1_minus7(self): self.assertEqual(add_ab(1,-7), -6)
Il codice sopra svolge le seguenti azioni:
- Importa il modulo `unittest` integrato in Python
- Importa la funzione `add_ab()` dal modulo `add`
- Definisce la classe di test `TestAdd` e una serie di test come metodi interni
Per impostare i test unitari per il tuo codice, devi prima definire una classe di test che erediti da `unittest.TestCase`. Ogni caso di test deve essere specificato come metodo all’interno della classe e deve iniziare con `test_`.
Nota: se i metodi non vengono chiamati con la convenzione `test_
Ora proviamo ad eseguire il modulo `test_add` dal terminale.
$ python test_add.py
Vedrai che non ci sarà alcun output e nessuno dei test verrà eseguito.
Perché succede? 🤔
Questo accade perché per eseguire i test unitari, dovresti avviare `unittest` come modulo principale quando esegui `test_add.py`, utilizzando il comando seguente.
$ python -m unittest test_add.py
Dopo aver eseguito il comando sopra, vedrai che tutti e tre i test sono stati eseguiti correttamente.
Output ... ---------------------------------------------------------------------- Ran 3 tests in 0.000s OK
Tuttavia, sarebbe molto più comodo eseguire i test direttamente quando avvii il modulo `test_add`, giusto? Nella prossima sezione vedremo come fare.
Utilizzare `if __name__ == ‘__main__’` per eseguire unittest come modulo principale
Se desideri eseguire tutti i test unitari quando il modulo viene avviato direttamente, puoi aggiungere la seguente condizione.
# example-2/test_add.py import unittest from add import add_ab class TestAdd(unittest.TestCase): def test_add_23(self): self.assertEqual(add_ab(2,3), 5) def test_add_19(self): self.assertEqual(add_ab(1,9), 10) def test_add_1_minus7(self): self.assertEqual(add_ab(1,-7), -6) # Avvia unittest come modulo principale if __name__ == '__main__': unittest.main()
La condizione nel codice qui sopra comunica all’interprete Python: se questo modulo viene eseguito direttamente, avvia il codice al suo interno, ovvero `unittest.main()`.
Ora puoi eseguire il modulo `test_add` dopo aver aggiunto le due righe di codice precedenti.
$ python test_add.py
▶️ L’esecuzione diretta del modulo `test_add` ora avvierà tutti e tre i test definiti.
Output ... ---------------------------------------------------------------------- Ran 3 tests in 0.000s OK
L’output `OK` indica che tutti i test sono stati eseguiti correttamente. I tre punti `…` mostrano che sono stati eseguiti tre test e che tutti sono stati superati.
Ora, modifichiamo il valore atteso nel test `test_add_1_minus7` impostandolo su 8. Poiché la funzione restituisce -6 in questo caso, dovremmo ottenere un test fallito.
def test_add_1_minus7(self): self.assertEqual(add_ab(1,-7), 8)
Come si può vedere nell’output seguente, otteniamo `.F.`. Dei tre test, uno è fallito (il secondo test). Il traceback mostra un `AssertionError` che indica `-6 != 8`.
Output .F. ====================================================================== FAIL: test_add_1_minus7 (__main__.TestAdd) ---------------------------------------------------------------------- Traceback (most recent call last): File "test_add.py", line 12, in test_add_1_minus7 self.assertEqual(add_ab(1,-7), 8) AssertionError: -6 != 8 ---------------------------------------------------------------------- Ran 3 tests in 0.021s FAILED (failures=1)
Un aspetto fondamentale da tenere presente è che i test non vengono eseguiti necessariamente nell’ordine in cui sono specificati nella classe di test. Nell’esempio precedente, `test_add_1_minus7` è definito come il terzo metodo nella classe di test, ma il test corrispondente è stato eseguito come secondo.
In sintesi
Spero che questa guida ti abbia fornito una comprensione chiara del funzionamento dell’istruzione `if __name__ == ‘__main__’` in Python.
Ecco un breve riepilogo dei concetti chiave da ricordare:
- L’interprete Python imposta la variabile `__name__` prima di avviare uno script Python.
- Quando un modulo viene eseguito direttamente, il valore di `__name__` è `__main__`.
- Quando importiamo un modulo all’interno di un altro script Python, il valore di `__name__` corrisponde al nome del modulo.
- Possiamo utilizzare `if __name__ == ‘__main__’` per controllare il flusso di esecuzione e quali parti del modulo vengono avviate durante l’esecuzione diretta e quando il modulo viene importato.
Ti consiglio anche di dare un’occhiata a questa guida dettagliata sui set in Python. Buon apprendimento! 🎉