В этой небольшой статье мы рассмотрим один из самых популярных "новичковых" вопросов - зачем нам конструкция if __name__ == "__main__".

Эта статья ориентирована на начинающих разработчиков, я пытаюсь объяснить тему максимально понятно и доступно. Поэтому где-то лукавлю, где-то преувеличиваю, но это для лучшего понимания, не кидайтесь ананасами :)


Прежде чем изучить конструкцию if __ name__ == __"main__", необходимо знать несколько вещей:

  • Интерпретатор Python выполняет весь код, который сможет найти в файле.

  • Когда Python запускает "исходный файл" в качестве основной программы, он присваивает переменной __name__ значение __main__

В языках программирования существует такое понятие, как точка входа. В некоторых языках программирования (C, C#, Go) конструкция if __name__ == "__main__" не требуется, потому что в самом начале разработки задается точка входа, без нее компилятор выдаст ошибку. Python же относится к этому лояльно и позволяет пользователю не указывать точку входу (Python в качестве точки входа считает первую строку), что может приводить к серьезным проблемам.

Также данная конструкция позволяет разделять файлы, чтобы они не пересекались при одновременной работе (при импорте модуля, либо при запуске самого модуля). 

Например, у нас есть две программы:

  1. (test.py) выводит значение переменной __name__, а затем строку "Hello world". 

  2. (test_2.py) импортирует модуль test.

Если в качестве исходной (откуда происходит запуск) программы мы выберем test.py, то на выводе получаем следующее:

Так как в качестве исходной программы мы выбрали test.py, интерпретатор Python присвоил значение переменной __name__: __main__. Теперь попробуем запустить test_2.py.

 

Как видим, вместо __main__ мы получили test. Почему это произошло? Потому что мы запустили модуль test, в котором есть строка print(__name__), но так как мы запустили этот код из другой программы (test_2.py), интерпретатор не вывел __main__.

Проще говоря, если мы запускаем программу через «побочную» программу, то переменной __name__ не будет задаваться значение __main__, что позволяет избежать лишнего срабатывания кода. Например:

Мы запустили файл test.py и получили на вывод результат сложения двух чисел и их разность. Также в конце вывели строку, говорящую, что запуск выполнен с помощью test.py. Если же мы импортирует этот модуль в программу test_2.py, то получим на вывод следующее:

А именно сообщение, что мы выполнили действия с помощью test.py, хотя в действительности это не так, ведь мы использовали test_2.py, а не test.py. Чтобы избежать подобного «лишнего» срабатывания фрагментов кода, необходимо в исходном файле (модуле) дописать конструкцию if __name__ == “__main__”. Должно получиться вот так:

Теперь при импортировании модуля test в test_2.py будет выполняться проверка значения переменной __name__. Запускаем наш test_2.py и видим, что теперь срабатывания print(“успешно выполнено с помощью test.py”) не произошло. 


Благодарю за прочтение статьи, надеюсь вы подчерпнули из неё что-то новое.

Пишите в комменты какую тему разобрать в следующий раз, всем добра!

Мой GitHub: https://github.com/Ryize

Комментарии (10)


  1. vadimr
    29.11.2022 11:36
    +2

    Это всё верно, но никак не отвечает на поставленный в заголовке статьи вопрос.

    Что такое “лишнее срабатывание кода”?

    Эта проверка выдумана людьми, привыкшими программировать на С-подобных процедурных языках, где исходный код организован в виде программы с одной точкой входа, чему на выходе отвечает монолитное приложение. Но это не единственный используемый в программировании способ организации программы.

    Программа на Питоне – это просто набор исполняемых операторов, к которым относятся в том числе и операторы def (между прочим, являющиеся не единственным способом создания функций).


  1. mentin
    29.11.2022 11:41
    +4

    Отлично. Я - target audience, на Питоне не пишу, но иногда что-то правлю, часто видел это заклинание.
    Я бы добавил в список "нескольких вещей" то что один и тот же файл может и часто используется и как главная программа и как библиотека. Во многих языках так обычно не делают, а без этого не надо проверять главная ли мы программа или нет.


    1. Vindicar
      29.11.2022 11:45

      Плюсом добавить что сценарий "главной программы" может запускать набор юнит-тестов на этот файл.


  1. aelaa
    29.11.2022 11:49

    если мы запускаем программу через «побочную» программу

    то у нас получается fork. Программа в данном контексте всегда одна.

    TL;DR: python зачем-то считает, что каждый модуль может быть запущен отдельно как самостоятельная программа. Самый верхнеуровневый модуль (аргумент команды python) будет иметь внутри себя __name__ = "__main__"


    1. AAbrosov
      29.11.2022 12:01
      +1

      Питон не "зачем-то" так считает, а просто дает возможность переиспользования кода.
      Вы можете во всех модулях добавлять этот оператор и использовать функции из других своих модулей


      1. aelaa
        29.11.2022 22:11

        Только все остальные языки как-то без этого обходятся. Потому что коду должно быть все равно как он запускается


  1. isBlaze
    29.11.2022 11:57
    +3

    Таким образом, если вы пишете скрипт, который не предполагает запуск как модуль, конструкция if __ name__ == __«main__» становится визуальным мусором и её следует избегать.


  1. cdriper
    29.11.2022 13:37
    +6

    Когда я познакомился с этим чудом первый раз, я подумал, что если даже вынести за скобки сомнительную изящность такого подхода, то почему это было не сделать через какую-то функцию в стандартной библиотеке? Зачем мне запоминать эти магические константы?

    if isMainModule(): ...


  1. Alexander_The_Great
    30.11.2022 11:50

    >Python же относится к этому лояльно и позволяет пользователю не указывать точку входу (Python в качестве точки входа считает первую строку), что может приводить к серьезным проблемам.

    Так вот она какая, эта "лояльность, а я-то думал...


  1. barker
    30.11.2022 11:55
    +2

    Как-то довольно путано расписана довольно простая суть: в питоне при импорте модуля его код выполняется целиком. Соответственно, if name == "__main__" это просто костыль, чтобы избежать побочных эффектов от этого (в случае если модуль содержит код, который имеет смысл выполнять только при запуске скрипта напрямую). Никакой "точки входа" или прочей магии тут нету...