if __name__ == «__main__» в Python: полное объяснение

Условный блок, начинающийся с if __name__ == "__main__" часто встречается в коде Python. Эта строка может выглядеть загадочно, и многие новички используют ее, не зная, что она делает и стоит ли ее использовать. Программисты, перешедшие на Python с других языков, также могут неправильно понимать эту идиому и использовать ее там, где это не нужно.

Из этой статьи вы узнаете о значении идиомы if__name__ == "__main__" в Python, а также о том, как и когда ее следует использовать.

Содержание

Разбираемся, что такое __name__ и «__main__»

Идиома if __name__ == "__main__" — это оператор if, который проверяет равенство.

Первым операндом, стоящим слева от оператора равенства ==, является атрибут __name__. В Python имена, начинающиеся с двойного подчеркивания, являются специальными идентификаторами. Атрибут __name__ есть у каждого модуля. Python устанавливает в качестве значения этой переменной имя модуля, которое система импорта Python использует для уникальной идентификации каждого модуля.

Но если модуль находится в среде кода верхнего уровня, то есть является модулем, используемым в качестве точки входа в программу, Python устанавливает в качестве значения атрибута __name__ строку "__main__".

Давайте рассмотрим несколько примеров. Создадим скрипт под названием exploring_name_main.py:

# exploring_name_main.py
import random
print(__name__)
print(random.__name__)

Этот скрипт можно запустить напрямую с помощью следующей команды в терминале:

$ python exploring_name_main.py

Вывод:

__main__
random

Скрипт exploring_name_main.py находится в среде кода верхнего уровня, так как является точкой входа в программу. Поэтому переменная __name__ установлена в строку "__main__".

Однако модуль random импортирован и не находится в среде кода верхнего уровня. Его атрибут __name__ устанавливается в имя модуля.

Далее мы создаем новый скрипт more_exploration.py, который импортирует первый скрипт:

# more_exploration.py
import exploring_name_main

Запустите этот скрипт с помощью следующей команды в терминале:

$ python more_exploration.py

Вывод:

exploring_name_main
random

Код модуля выполняется, когда модуль импортируется. Поэтому при запуске more_exploration.py код отображает вывод двух вызовов print() в exploring_name_main.py. Поскольку exploring_name_main.py больше не является точкой входа в программу, его атрибут __name__ устанавливается в имя скрипта вместо "__main__".

Условный блок if __name__ == «__main__»

Переменная __name__ может использоваться для определения того, является ли модуль главной точкой входа в программу. Таким образом, модуль может содержать код, который будет выполняться только при непосредственном запуске в качестве скрипта, но не при импорте. Любой код, который должен выполняться только при непосредственном запуске скрипта, включается в условный блок if __name__ == "__main__":

# exploring_name_main.py
import random
print(__name__)
print(random.__name__)
number = random.randint(1, 10)
if __name__ == "__main__":
    print("This script is in the top-level code environment")
    print(f"The number is {number}")

Код в exploring_name_main.py теперь включает условный блок if __name__ == "__main__". Давайте посмотрим, повлияет ли это на что-нибудь при выполнении скрипта:

$ python exploring_name_main.py

Вывод:

__main__
random
This script is in the top-level code environment
The number is 10

При непосредственном запуске скрипта переменная __name__ устанавливается в строку "__main__". Поэтому условие в операторе if оценивается как True, и Python выполняет код в блоке if.

Однако, когда модуль импортируется, __name__ устанавливается в имя модуля, и программа не выполняет блок if. Вспомните, что скрипт more_exploration.py импортирует exploring_name_main:

$  python more_exploration.py

Вывод:

exploring_name_main
random

Программа не вызывает функции print() в exploring_name_main.py. Они находятся в условном блоке, который не выполняется, поскольку __name__ не равно "__main__".

Лучшие практики и советы по использованию if __name__ == «__main__»

Идиома Python if __name__ == "__main__" используется, если код должен выполняться только тогда, когда файл запускается как скрипт, а не импортируется как модуль. Различие между терминами «скрипт» и «модуль» заключается только в том, как используется файл. Оба термина относятся к файлам с расширением .py.

Чаще всего скрипт содержит переменные, функции и классы, которые могут использоваться в других программах. Вот пример использования скрипта с именем shapes.py:

# shapes.py
import math
def find_area_of_circle(radius):
    return math.pi * radius ** 2
def find_area_of_rectangle(width, height):
    return width * height
if __name__ == "__main__":
    shape = int(input("Enter 1 for circle, 2 for rectangle: "))
    if shape == 1:
        radius = int(input("Enter radius: "))
        print(f"The area of the circle is {find_area_of_circle(radius)}")
    elif shape == 2:
        width = int(input("Enter width: "))
        height = int(input("Enter height: "))
        print(f"The area of the rectangle is {find_area_of_rectangle(width, height)}")
Enter 1 for circle, 2 for rectangle: 2
Enter width: 10
Enter height: 20
The area of the rectangle is 200

Этот код не нуждается в идиоме if __name__ == "__main__", если предполагается всегда запускать его как скрипт. Однако включение этого условного оператора позволяет импортировать код как модуль без выполнения строк в блоке if.

Рассмотрим другой скрипт с именем more_shapes.py:

# more_shapes.py
import shapes
radius = 5
print(f"The area of the circle defined in 'more_shapes.py' is: "
      f"{shapes.find_area_of_circle(radius)}")
The area of the circle defined in 'more_shapes.py' is: 78.53981633974483

Этот новый скрипт, more_shapes.py, имеет доступ к функциям, определенным в shapes.py, благодаря оператору import. Однако код в блоке if __name__ == "__main__" в shapes.py не выполняется. Без оператора if в shapes.py при импорте модуля выполнялся бы весь код.

Блок if __name__ == "__main__" часто используется для пользовательского ввода. Пользовательский ввод опускается, если файл импортируется как модуль, но включается, если выполняется непосредственно как код верхнего уровня.

Использование функции main()

Лучше всего включать в блок if __name__ == "__main__" как можно меньше инструкций, так как это делает код более читабельным. Обычный способ добиться этого — создать функцию, которая вызывается в условном блоке. Обычно эта функция называется main(), но можно использовать любое имя:

# shapes.py
import math
def find_area_of_circle(radius):
    return math.pi * radius ** 2
def find_area_of_rectangle(width, height):
    return width * height
def main():
    shape = int(input("Enter 1 for circle, 2 for rectangle: "))
    if shape == 1:
        radius = int(input("Enter radius: "))
        print(f"The area of the circle is {find_area_of_circle(radius)}")
    elif shape == 2:
        width = int(input("Enter width: "))
        height = int(input("Enter height: "))
        print(f"The area of the rectangle is {find_area_of_rectangle(width, height)}")
       
if __name__ == "__main__":
    main()

Код в функции main() — это тот же код, который был включен непосредственно в блок if __name__ == "__main__" в предыдущей версии кода.

В Python функция main() не требуется в качестве основной точки входа в программу, в отличие от некоторых других языков программирования. Поэтому использование функции main() и идиомы if __name__ == "__main__" необязательно, и нужно только в том случае, если код предполагается использовать и как отдельный скрипт, и как модуль.

Еще один распространенный случай использования if __name__ == "__main__" в Python — это включение тестов в скрипт. Тесты будут выполняться при непосредственном выполнении скрипта, но не при его импорте из другого модуля. Однако, хотя такой способ подходит для простых случаев, лучше включать тесты в отдельный модуль, предназначенный для тестирования.

Заключение

Идиома Python if __name__ == "__main__" полезна для включения кода, который выполняется только при непосредственном запуске скрипта, но не при его импорте. Интерпретатор Python устанавливает переменную __name__ в имя модуля, если он импортирован, и в строку "__main__", если модуль является основной точкой входа в программу.

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

Перевод статьи “if __name__ == «__main__» Python: Complete Explanation”.