Выражение if __name__ == "__main__" в Python встречается довольно часто, и вы задаёте вопрос: "Зачем оно?". Давайте разберём на практике, как оно работает и зачем вообще нужно. Приступим!
Python-модуль — это файл с расширением .py. Чтобы создать такой модуль, достаточно написать код в файле и присвоить ему имя с соответствующим расширением. Модули могут быть импортированы в другие модули или запущены непосредственно на исполнение.
__name__ — это специальный атрибут, значение которого соответствует названию текущего модуля. Но если модуль запускается на исполнение сам по себе, то вместо названия файла __name__ принимает в качестве значения строку "__main__".
Разберём небольшой пример для понимания. Допустим, мы хотим создать два модуля: foo и bar. Код модуля foo:
__name__ — это специальный атрибут, значение которого соответствует названию текущего модуля. Но если модуль запускается на исполнение сам по себе, то вместо названия файла __name__ принимает в качестве значения строку "__main__".
Разберём небольшой пример для понимания. Допустим, мы хотим создать два модуля: foo и bar. Код модуля foo:
# foo.py
import bar
print("foo.__name__ set to ", __name__)
Код модуля bar:
# bar.py
print("bar.__name__ set to ", __name__)
При запуске модуля bar.py на исполнение его атрибуту __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__ устроен именно таким образом, то поймём, что иногда мы хотим написать программу, которая могла бы использоваться и как встраиваемый модуль, и как самостоятельный скрипт.
Такой подход очень удобен для быстрой разработки, тестирования и отладки кода. Например, можно создать отдельный модуль, в котором разом будут отрабатывать все юнит-тесты при его запуске.
Вообще, это довольно удобно, когда мы можем варьировать режим запуска кода буквально одной строкой.
Выводы
Если мы задумаемся над тем, почему атрибут __name__ устроен именно таким образом, то поймём, что иногда мы хотим написать программу, которая могла бы использоваться и как встраиваемый модуль, и как самостоятельный скрипт.
Такой подход очень удобен для быстрой разработки, тестирования и отладки кода. Например, можно создать отдельный модуль, в котором разом будут отрабатывать все юнит-тесты при его запуске.
Вообще, это довольно удобно, когда мы можем варьировать режим запуска кода буквально одной строкой.
Выводы
- Каждый модуль в Python обладает специальным атрибутом __name__. Он принимает значение "__main__", когда модуль запускается напрямую. Если же модуль используется в другой программе, значением атрибута будет именем самого модуля.
- Мы используем блок if __name__ == "__main__" для предотвращения запуска определённого кода именно при импорте модуля.
Источник: Medium