Зачем нам if __name__ == "__main__"
Выражение if __name__ == "__main__"
в Python встречается довольно часто, и вы задаёте вопрос: "Зачем оно?". Давайте разберём на практике, как оно работает и зачем вообще нужно. Приступим!
Python-модуль — это файл с расширением .py
. Чтобы создать такой модуль, вам достаточно написать код в файле и присвоить ему имя с соответствующим расширением. Модули могут быть импортированы в другие модули или запущены непосредственно на исполнение.
__name__
— это специальный атрибут, значение которого соответствует названию текущего модуля. Но если модуль запускается на исполнение сам по себе, то вместо названия файла __name__
он принимает в качестве значения строку "__main__"
.
Разберём небольшой пример для понимания. Допустим, мы хотим создать два модуля: foo
и bar
. Код модуля foo
:
# foo.py import bar print("foo.__name__ set to ", __name__)
# bar.py print("bar.__name__ set to ", __name__)
При запуске модуля bar на исполнение его атрибуту __name__
будет присвоено значение "__main__"
:
python bar.py >>> bar.__name__ set to __main__
Однако, при таком же вызове модуля foo
значение атрибута __name__
модуля bar
устанавливается эквивалентно его же имени, то есть bar
:
python foo.py >>> bar.__name__ set to bar foo.__name__ set to __main__
Таким образом, мы можем проверить способ исполнения нашего модуля, делается это напрямую или путём импорта в другой модуль:
if __name__ == "__main__": ...
Используя такую проверку, модуль по сути проверяет, как именно он используется: в качестве основной программы, либо же вспомогательно в другой программе, в которую этот модуль импортирован.
Когда один модуль импортируется в другой, импортируются также все его функции и классы, а также отрабатывает верхнеуровневый код (в глобальном контексте). Рассмотрим следующие два модуля для наглядной иллюстрации процесса:
# Модуль person.py def creds(): name = "Oleg" age = 100 print(f"Инфа о человеке: {name}, {age}") print("Какая-то строка с вызовом в глобальном контексте") if __name__ == "__main__": print("Модуль person исполняется напрямую") else: print("Модуль person был импортирован в другой модуль")
# Модуль utility.py import person person.creds() if __name__ == "__main__": print("Модуль utility исполняется напрямую") else: print("Модуль utility был импортирован в другой модуль")
При прямом исполнении модуля person
атрибуту __name__
будет присвоено значение "__main__
", в связи с чем мы увидим следующий вывод:
python person.py >>> Какая-то строка с вызовом в глобальном контексте Модуль person исполняется напрямую
А при исполнении модуля utility
напрямую атрибуту __name__
модуля person
будет присвоено значение "person".
В это же время, атрибут __name__
модуля utility
получит значение "__main__"
. И мы получим такой результат:
python utility.py >>> Какая-то строка с вызовом в глобальном контексте Модуль person был импортирован в другой модуль Инфа о человеке: Олег, 100 Модуль utility исполняется напрямую
Почему всё устроено именно так?
Если мы задумаемся над тем, почему атрибут __name__
устроен именно таким образом, то поймём, что иногда мы хотим написать программу, которая могла бы использоваться и как встраиваемый модуль, и как самостоятельный скрипт.
Такой подход очень удобен для быстрой разработки, тестирования и отладки кода. Например, можно создать отдельный модуль, в котором разом будут отрабатывать все юнит-тесты при его запуске.
Вообще, это довольно удобно, когда мы можем варьировать режим запуска кода буквально одной строкой.
- Каждый модуль в Python обладает специальным атрибутом
__name__
. Он принимает значение"__main__"
, когда модуль запускается напрямую. Если же модуль используется в другой программе, значением атрибута будет именем самого модуля. - Мы используем блок
if __name__ == "__main__"
для предотвращения запуска определённого кода именно при импорте модуля.
Источник: Medium