U ovom vodiču razumećete funkcionalnost i važnost konstrukcije `if __name__ == ‘__main__’` u Pythonu.
Da li ste ikada pregledali Python kod sa raznim modulima?
Ako jeste, verovatno ste primetili da se `if __name__ == ‘__main__’` uslov pojavljuje u jednom ili više modula. U narednih nekoliko minuta razjasnićemo šta ovaj uslov znači i pogledati primere gde može biti od koristi.
Započnimo!
Kakav je značaj `__name__` u Pythonu?
U Pythonu, modul je `.py` datoteka koja sadrži definicije funkcija, skup iskaza za evaluaciju i još mnogo toga. Na primer, ako imamo datoteku nazvanu `hello_world.py`, nazivamo je `hello_world.py` datotekom ili `hello_world` modulom.
Kada pokrenete Python modul, Python interpreter postavlja vrednosti za nekoliko specijalnih promenljivih pre izvršenja: `__name__` je jedna od njih. Ključ za razumevanje značaja `__name__` je razumevanje kako uvozi funkcionišu u Pythonu.
📁 Preuzmite kod za ovaj odeljak ovde.
Idite u direktorijum Primer-1. Tamo se nalazi datoteka `module1.py`. Promenljiva `__name__` je smeštena u imenski prostor trenutnog modula.
Ovaj modul ispisuje liniju teksta, nakon čega sledi vrednost promenljive `__name__`.
# example-1/module1.py print("Ovo je module1.") print(f"Promenljiva __name__ modula 1 je: {__name__}.")
Sada, pokrenimo `module1` iz komandne linije.
$ python module1.py
U izlazu vidimo da je promenljiva `__name__` postavljena na `__main__`.
Ovo je module1. Promenljiva __name__ modula 1 je: __main__.
Uvoz modula u Pythonu
Pored pokretanja Python modula, ponekad ćete možda želeti da koristite funkcionalnost iz drugog Python modula unutar trenutnog modula. Python to omogućava pomoću uvoza.
Uvozi vam dozvoljavaju da ponovo koristite funkcionalnost drugog modula – tako što ćete ga uvesti u opseg trenutnog modula – bez potrebe da ponovo pišete kod.
Datoteka `module2.py` sadrži sledeće. Unutar nje smo uvezli `module1`.
# example-1/module2.py import module1 # module1 je uvezen print(f"Ovo je module2") print(f"Promenljiva __name__ modula 2 je: {__name__}.")
Pokrećemo `module2.py` i posmatramo izlaz.
$ python module2.py
U izlazu ispod:
- Vidimo da se `module1` pokreće kada ga uvezemo unutar `module2`, a odgovarajući izlaz se štampa.
- Ali ovog puta, promenljiva `__name__` nije `__main__` već `module1`.
- Pošto smo direktno pokrenuli `module2`, promenljiva `__name__` koja odgovara modulu je sada `__main__`.
Izlaz: Ovo je module1. Promenljiva __name__ modula 1 je: module1. Ovo je module2 Promenljiva __name__ modula 2 je: __main__.
💡 Ključna ideja:
– Ako se modul pokreće direktno, njegova promenljiva `__name__` je postavljena na `__main__`.
– Ako je modul uvezen unutar drugog modula, njegova `__name__` se postavlja na ime modula.
Primer `if __name__ == ‘__main__’` u Pythonu
U ovom odeljku videćemo praktičan slučaj upotrebe uslova `if __name__ == ‘__main__’`. Definisaćemo jednostavnu funkciju, a zatim napisati jedinične testove kako bismo proverili da li funkcija radi kako se očekuje.
📁 Preuzmite kod i pratite ga.
Kod za ovaj odeljak se nalazi u folderu `example-2`.
Ovde je `add.py` Python datoteka koja sadrži definiciju funkcije `add_ab()`. Funkcija `add_ab()` uzima dva broja i vraća njihov zbir.
# example-2/add.py def add_ab(a,b): return a + b
Koristićemo Pythonov modul `unittest` da testiramo funkciju `add_ab()`.
Pisanje test slučajeva za Python funkciju
Pogledajte isečak koda ispod, koji sadrži sadržaj modula `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)
Gornji kod radi sledeće:
- Uvozi Pythonov ugrađeni modul za testiranje jedinica
- Uvozi funkciju `add_ab()` iz modula za dodavanje
- Definiše test klasu `TestAdd` i skup test slučajeva kao metode unutar test klase
Da biste podesili jedinične testove za svoj kod, prvo treba da definišete test klasu koja nasleđuje `unittest.TestCase`. Svi test slučajevi treba da budu specificirani kao metode unutar klase i treba da počnu sa `test_`.
Napomena: Ako ne nazovete metode kao `test_
Sada pokušajmo da pokrenemo `test_add` modul sa terminala.
$ python test_add.py
Videćete da nema izlaza i da nijedan od testova nije pokrenut.
Zašto je to tako?🤔
To je zato što da biste pokrenuli jedinične testove, trebalo bi da pokrenete `unittest` kao glavni modul dok pokrećete `test_add.py`, koristeći naredbu ispod.
$ python -m unittest test_add.py
Nakon pokretanja gornje komande, vidimo da su sva tri testa uspešno izvršena.
Izlaz: ... ---------------------------------------------------------------------- Ran 3 tests in 0.000s OK
Međutim, bilo bi zgodno pokrenuti testove kada se pokrene ovaj modul `test_add`, zar ne? Hajde da naučimo kako to da uradimo u sledećem odeljku.
Korišćenje `if __name__ == ‘__main__’` za pokretanje `unittest`-a kao glavnog modula
Ako želite da pokrenete sve jedinične testove kada se modul pokreće direktno, možete dodati uslov.
# 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) # Pokreni unittest kao glavni modul if __name__ == '__main__': unittest.main()
Uslov u gornjem isečku koda govori Python interpretatoru: Ako se ovaj modul pokreće direktno, onda pokrenite kod unutar `unittest.main()`.
Možete pokrenuti modul `test_add` nakon što dodate gornja dva reda koda.
$ python test_add.py
▶ Direktno pokretanje modula za dodavanje testa sada pokreće sva tri testa koja smo definisali.
Izlaz: ... ---------------------------------------------------------------------- Ran 3 tests in 0.000s OK
Gornji izlaz OK pokazuje da su svi testovi uspešno izvršeni. Tri tačke `…` označavaju da su tri testa izvršena i da su svi prošli.
Sada, hajde da promenimo očekivanu povratnu vrednost `test_add_1_minus7` na 8. Pošto funkcija vraća -6 u ovom slučaju, trebao bi postojati jedan neuspešan test.
def test_add_1_minus7(self): self.assertEqual(add_ab(1,-7), 8)
Kao što se vidi u donjem izlazu, dobijamo `.F.`, od tri testa, jedan od njih nije uspeo (drugi test), a u povratnom tragu dobijamo `AssertionError` koji navodi `-6 != 8`.
Izlaz: .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)
Jedna važna stvar koju treba napomenuti je da se testovi ne izvršavaju nužno istim redosledom kojim su navedeni u test klasi. U gornjem primeru, `test_add_1_minus7` je definisan kao treći metod u test klasi, ali je odgovarajući test pokrenut drugi.
Sumirajući
Nadam se da vam je ovaj vodič pomogao da razumete kako funkcioniše uslov `if __name__ == ‘__main__’` u Pythonu.
Evo kratkog rezimea ključnih zaključaka:
- Python interpreter postavlja promenljivu `__name__` pre izvršavanja Python skripte.
- Kada direktno pokrenete modul, vrednost `__name__` je `__main__`.
- Kada uvezete modul unutar druge Python skripte, vrednost `__name__` je ime modula.
- Možete koristiti `if __name__ == ‘__main__’` da kontrolišete izvršenje i koji delovi modula se pokreću tokom direktnog i uvezenog pokretanja, respektivno.
Zatim pogledajte ovaj detaljni vodič o Python skupovima. Srećno učenje!🎉