Статьи
November 7, 2022

Зачем нам 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:

# 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__" для предотвращения запуска определённого кода именно при импорте модуля.

PythonTalk в Telegram

Чат PythonTalk в Telegram

Предложить материал | Поддержать канал

Источник: Medium