Zrozumienie, czy __name__ == '__main__’ w Pythonie

W tym przewodniku zrozumiesz funkcjonalność i znaczenie if __name__ == '__main__’ w Pythonie.

Czy kiedykolwiek przeglądałeś bazę kodu Pythona z różnymi modułami?

Jeśli tak, prawdopodobnie spotkałbyś się z warunkowym __name__ == '__main__’ w jednym lub kilku modułach. W ciągu następnych kilku minut wyjaśnimy, co oznacza powyższy warunek warunkowy i przyjrzymy się przykładowi, w którym może to być pomocne.

Zaczynajmy!

Jakie jest znaczenie __name__ w Pythonie?

W Pythonie moduł jest plikiem .py zawierającym definicje funkcji, zestaw wyrażeń do oceny i nie tylko. Na przykład, jeśli mamy plik o nazwie hello_world.py, nazywamy go plikiem hello_world.py lub modułem hello_world.

Kiedy uruchamiasz moduł Pythona, interpreter Pythona ustawia wartości kilku specjalnych zmiennych przed wykonaniem: __name__ jest jedną z nich. Kluczem do zrozumienia znaczenia __name__ jest zrozumienie, jak działają importy w Pythonie.

📁 Pobierz kod do tej sekcji tutaj.

Udaj się do folderu przykład-1. Mamy plik module1.py. Zmienna __name__ znajduje się w przestrzeni nazw bieżącego modułu.

Ten moduł wypisuje wiersz, po którym następuje wartość zmiennej __name__.

# example-1/module1.py
print("This is module1.")
print(f"The __name__ variable of module 1 is: {__name__}.")

Teraz uruchommy module1 z wiersza poleceń.

$ python module1.py

Na wyjściu widzimy, że zmienna __name__ jest ustawiona na __main__.

This is module1.
The __name__ variable of module 1 is: __main__.

Importowanie modułów w Pythonie

Oprócz uruchomienia modułu Pythona, czasami możesz chcieć użyć funkcjonalności z innego modułu Pythona wewnątrz bieżącego modułu. Python ułatwia to poprzez importy.

Importy umożliwiają ponowne wykorzystanie funkcji innego modułu — poprzez zaimportowanie go do zakresu bieżącego modułu — bez konieczności przepisywania kodu.

Plik module2.py zawiera następujące elementy. W środku zaimportowaliśmy moduł1. moduł2.

# example-1/module2.py

import module1 # module1 is imported

print(f"This is module2")
print(f"The __name__ variable of module2 is: {__name__}.")

Uruchamiamy module2.py i obserwujemy wyjście.

$ python module2.py

W poniższym wyjściu:

  • Widzimy, że module1 jest uruchamiany pod maską, gdy importujemy go do modułu module2, a odpowiednie dane wyjściowe są drukowane.
  • Ale tym razem zmienna __name__ to nie __main__, ale moduł1.
  • Ponieważ uruchomiliśmy module2 bezpośrednio, zmienna __name__ odpowiadająca modułowi to teraz __main__.
Output

This is module1.
The __name__ variable of module 1 is: module1.
This is module2
The __name__ variable of module2 is: __main__.

💡 Kluczowa idea:

– Jeśli moduł jest uruchamiany bezpośrednio, jego zmienna __name__ jest ustawiona na __main__.

– Jeśli moduł jest importowany wewnątrz innego modułu, jego __name__ jest ustawiana na nazwę modułu.

Przykład, jeśli __name__==’__main__’ w Pythonie

W tej sekcji zobaczymy praktyczny przypadek użycia warunkowego if __name__ == '__main__’. Zdefiniujemy prostą funkcję, a następnie napiszemy testy jednostkowe, aby sprawdzić, czy funkcja działa zgodnie z oczekiwaniami.

📁 Pobierz kod i postępuj zgodnie z instrukcjami.

Kod do tej sekcji można znaleźć w folderze example-2.

Tutaj add.py jest plikiem Pythona, który zawiera definicję funkcji add_ab(). Funkcja add_ab() przyjmuje dowolne dwie liczby i zwraca ich sumę.

# example-2/add.py

def add_ab(a,b):
    return a + b

Wykorzystamy moduł testów jednostkowych Pythona do przetestowania funkcji add_ab().

Pisanie przypadków testowych dla funkcji Pythona

Spójrz na poniższy fragment kodu, zawierający zawartość modułu 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)
    

Powyższy kod wykonuje następujące czynności:

  • Importuje wbudowany moduł testów jednostkowych Pythona
  • Importuje funkcję add_ab() z modułu add
  • Definiuje klasę testową TestAdd i zestaw przypadków testowych jako metody w klasie testowej

Aby skonfigurować testy jednostkowe dla kodu, należy najpierw zdefiniować klasę testową, która dziedziczy po unittest.TestCase. Wszystkie przypadki testowe powinny być określone jako metody wewnątrz klasy i powinny zaczynać się od test_.

Uwaga: Jeśli nie nazwiesz metod jako test_, zobaczysz, że odpowiednie testy nie zostaną wykryte, a zatem nie zostaną uruchomione.

Teraz spróbujmy uruchomić moduł test_add z terminala.

$ python test_add.py

Zobaczysz, że nie ma danych wyjściowych i żaden z testów nie został uruchomiony.

Dlaczego tak jest?🤔

Dzieje się tak dlatego, że aby uruchomić testy jednostkowe, powinieneś uruchomić unittest jako główny moduł podczas uruchamiania test_add.py, używając poniższego polecenia.

$ python -m unittest test_add.py

Po uruchomieniu powyższego szczegółowego polecenia widzimy, że wszystkie trzy testy zakończyły się pomyślnie.

Output
...
----------------------------------------------------------------------
Ran 3 tests in 0.000s

OK

Jednak wygodniej będzie uruchamiać testy, gdy ten moduł test_add jest uruchomiony, tak? Nauczmy się, jak to zrobić w następnej sekcji.

Użycie if __name__ == '__main__’ do uruchomienia testu jednostkowego jako modułu głównego

Jeśli chcesz uruchomić wszystkie testy jednostkowe, gdy moduł działa bezpośrednio, możesz dodać warunek.

# 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)

# Run unittest as the main module
if __name__ == '__main__':
        unittest.main()

Warunek w powyższym fragmencie kodu mówi interpreterowi Pythona: Jeśli ten moduł jest uruchamiany bezpośrednio, uruchom znajdujący się w nim kod. test_jednostki.main().

Możesz uruchomić moduł test_add po dodaniu powyższych dwóch linii kodu.

$ python test_add.py

▶️ Bezpośrednie uruchomienie modułu dodawania testu uruchamia teraz wszystkie trzy zdefiniowane przez nas testy.

Output
...
----------------------------------------------------------------------
Ran 3 tests in 0.000s

OK

Powyższe dane wyjściowe OK wskazują, że wszystkie testy zostały wykonane pomyślnie. Trzy kropki… wskazują, że przeprowadzono trzy testy i wszystkie zaliczone.

Teraz zmieńmy oczekiwaną wartość zwracaną test_add_1_minus7 na 8. Ponieważ funkcja zwraca – w tym przypadku 6, powinien być jeden test zakończony niepowodzeniem.

def test_add_1_minus7(self):
        self.assertEqual(add_ab(1,-7), 8)

Jak widać na poniższym wyjściu, otrzymujemy .F., z trzech testów, wzór jeden z nich nie powiódł się (drugi test), a w śledzeniu otrzymujemy AssertionError stwierdzający – 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)

Ważną rzeczą, na którą należy zwrócić uwagę, jest to, że testy niekoniecznie są uruchamiane w tej samej kolejności, w jakiej zostały określone w klasie testów. W powyższym przykładzie test_add_1_minus7 jest zdefiniowany jako trzecia metoda w klasie testowej, ale odpowiedni test został uruchomiony jako drugi.

Podsumowując

Mam nadzieję, że ten samouczek pomógł ci zrozumieć, jak warunek warunkowy if __name__ == '__main__’ działa w Pythonie.

Oto krótkie podsumowanie najważniejszych wniosków:

  • Interpreter Pythona ustawia zmienną __name__ przed wykonaniem skryptu Pythona.
  • Kiedy uruchamiasz moduł bezpośrednio, wartość __name__ to __main__.
  • Kiedy importujesz moduł do innego skryptu Pythona, wartością __name__ jest nazwa modułu.
  • Możesz użyć if __name__ == '__main__’ do kontrolowania wykonania i które części modułu są uruchamiane odpowiednio podczas bezpośredniego i importowanego przebiegu.

Następnie zapoznaj się z tym szczegółowym przewodnikiem po zestawach Pythona. Miłej nauki!🎉