Najdziwniejsza linia w Pythonie bez tajemnic
Otwórz prawie dowolny plik Pythona, a prędzej czy później zobaczysz na dole to:
if __name__ == "__main__":
main()
Wygląda to jak magiczny szablonowy kod. W rzeczywistości to bardzo praktyczna funkcja, gdy wiesz, co robi, a istnieje dlatego, że Python nie oddziela "skryptów" od "bibliotek".
Punkt wyjścia: dwa sposoby użycia pliku
Każdego pliku .py w Pythonie można użyć na dwa różne sposoby:
- Jako skryptu: uruchamiasz go bezpośrednio przez
python3 file.py. - Jako modułu: inny plik importuje go przez
import file.
Język nie każe ci deklarować, który z nich piszesz. Każdy plik może skończyć, robiąc jedno i drugie.
Weźmy plik o nazwie math_helpers.py:
# math_helpers.py
def mean(values):
return sum(values) / len(values)
def median(values):
s = sorted(values)
mid = len(s) // 2
if len(s) % 2 == 0:
return (s[mid - 1] + s[mid]) / 2
return s[mid]
# Szybki test w trakcie pisania kodu
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
print("mean:", mean(numbers))
print("median:", median(numbers))
Jeśli uruchomisz ten plik bezpośrednio, wypisze wyniki testu, i dobrze. Ale jeśli jakiś inny plik zrobi import math_helpers, te instrukcje print wykonają się podczas importu. Każdy użytkownik modułu zobaczy twoje robocze wyniki. Niedobrze.
Czym jest __name__
Każdy moduł Pythona ma wbudowaną zmienną o nazwie __name__. Python ustawia ją automatycznie:
- Gdy plik jest importowany,
__name__przyjmuje nazwę importu modułu, w przykładzie powyżej"math_helpers". - Gdy plik jest uruchamiany bezpośrednio, Python ustawia
__name__na specjalny napis"__main__".
To daje ci sposób, żeby sprawdzić, w którym trybie jesteś. Opakuj kod "tylko dla skryptu" w warunek:
# math_helpers.py
def mean(values):
return sum(values) / len(values)
def median(values):
s = sorted(values)
mid = len(s) // 2
if len(s) % 2 == 0:
return (s[mid - 1] + s[mid]) / 2
return s[mid]
if __name__ == "__main__":
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
print("mean:", mean(numbers))
print("median:", median(numbers))
Teraz python3 math_helpers.py wypisuje wyniki testu. Ale import math_helpers z innego pliku całkowicie pomija ten blok: funkcje są dostępne i nie wykonuje się nic niechcianego.
Częsty towarzysz: funkcja main()
Większość prawdziwych skryptów dorasta do osobnej funkcji main(), a blok strażnika zostaje malutki:
# process_orders.py
import sys
def load_orders(path):
with open(path) as f:
return [line.strip() for line in f if line.strip()]
def process(orders):
for order in orders:
print(f"Processing {order}")
def main():
if len(sys.argv) < 2:
print("Usage: python3 process_orders.py <file>")
sys.exit(1)
orders = load_orders(sys.argv[1])
process(orders)
if __name__ == "__main__":
main()
Po co funkcja main(), zamiast wpisać logikę bezpośrednio pod strażnika if?
- Testowalność. Możesz zaimportować moduł i wywołać
main()(albo dowolną funkcję pomocniczą) z testów. - Zmienne lokalne. Wszystko zdefiniowane w
main()jest zmienną lokalną, a nie nazwą na poziomie modułu. To zapobiega przypadkowym kolizjom nazw i porządkuje publiczny interfejs modułu. - Czytelność. Blok strażnika ma teraz dwie linie: jasny "punkt wejścia skryptu" zamiast sterty logiki.
Szybka demonstracja
Możesz zobaczyć to zachowanie bezpośrednio:
Gdy uruchomisz powyższy fragment w Pythonie, wypisze __name__ is: __main__ oraz "being run as a script." Gdyby jakiś inny plik zaimportował ten, ten sam warunek wypisałby drugą gałąź.
Kiedy strażnik nie jest potrzebny
Mnóstwo plików Pythona nigdy go nie dostaje. Krótkie skrypty, których nikt nigdy nie zaimportuje, dobrze się bez niego obywają:
# one_off_rename.py
import os
for name in os.listdir("."):
if name.endswith(".txt"):
os.rename(name, name.lower())
To całkowicie w porządku. Nie budujesz biblioteki; nikt tego nie zaimportuje. Ale gdy tylko w pliku pojawia się logika wielokrotnego użytku, a obok niej chcesz zostawić kod z efektami ubocznymi, sięgnij po strażnika.
Punkty wejścia dla instalowanych pakietów
Gdy publikujesz kod jako prawdziwy pakiet, istnieje bardziej formalny mechanizm: entry_points w metadanych pakietu, które mapują polecenie na funkcję. Osoby instalujące twój pakiet dostają polecenie powłoki, które bezpośrednio wywołuje tę funkcję. Ale dla skryptów uruchamianych z folderu na własnym komputerze standardowym narzędziem jest strażnik __main__.
Podsumowanie rozdziału
Masz teraz:
- Funkcje, żeby nazywać swoją logikę.
*args/**kwargsdo elastycznych wywołań.- Lambdy do jednorazowych funkcji.
- Dekoratory i adnotacje typów, żeby opakowywać i dokumentować te funkcje.
- Moduły, pip i środowiska wirtualne, żeby dzielić kod na pliki i projekty.
- Strażnika
__main__, dzięki któremu skrypty i moduły mogą współistnieć.
Dalej: klasy
Do tej pory funkcje pracowały głównie ze zwykłymi danymi: słownikami, listami, krotkami. Następny rozdział wprowadza klasy, czyli sposób Pythona na powiązanie danych z zachowaniem, oraz miejsce, gdzie mieszkają pojęcia takie jak self, __init__, dziedziczenie i dataclasses.
Najczęściej zadawane pytania
Co robi if __name__ == '__main__'?
if __name__ == '__main__'?Uruchamia blok pod spodem tylko wtedy, gdy plik jest wykonywany bezpośrednio (a nie importowany jako moduł). Dzięki temu możesz napisać plik .py, który da się uruchomić jako skrypt albo zaimportować dla jego funkcji i klas, bez wykonywania akcji skryptu podczas importu.
Czy Python potrzebuje funkcji main?
Nie. Pliki Pythona wykonują się automatycznie od góry do dołu. Ale gdy tylko plik zawiera logikę, którą chcesz też importować, strażnik if __name__ == '__main__' staje się ważny, a umieszczanie głównej pracy skryptu w funkcji main() to często idący z nim w parze nawyk.
Czym różni się __name__ od __main__?
__name__ od __main__?__name__ to specjalna zmienna, którą Python ustawia w każdym module. Jeśli plik jest importowany, __name__ to nazwa modułu (na przykład 'util'). Jeśli plik jest uruchamiany bezpośrednio, Python ustawia __name__ na napis '__main__'. Warunek if porównuje te dwie wartości.