Короткий ответ
Это шаблонный код, который защищает пользователей от случайного вызова сценария, когда они этого не собирались. Вот некоторые типичные проблемы, возникающие при отсутствии защиты в скрипте:
Если вы импортируете скрипт без защиты в другой скрипт (например, import my_script_without_a_name_eq_main_guard
), то второй скрипт инициирует запуск первого во время импорта и с использованием аргументов командной строки второго скрипта. Это почти всегда ошибка.
Если у вас есть собственный класс в сценарии без защиты и вы сохранили его в файле pickle, то его извлечение в другом сценарии вызовет импорт сценария без защиты с теми же проблемами, что описаны в предыдущем пункте.
Длинный ответ
Чтобы лучше понять, почему и как это важно, нам нужно сделать шаг назад, чтобы понять, как Python инициализирует скрипты и как это взаимодействует с механизмом импорта модуля.
Всякий раз, когда интерпретатор Python читает исходный файл, он делает две вещи:
он устанавливает несколько специальных переменных, например __name__
, а затем
он выполняет весь код, найденный в файле.
Давайте посмотрим, как это работает и как это связано с вашим вопросом о __name__
проверках, которые мы всегда видим в скриптах Python.
Образец кода
Давайте воспользуемся немного другим примером кода, чтобы изучить, как работают импорт и скрипты. Предположим, следующее находится в файле с именем foo.py
.
# Suppose this is foo.py.
print("before import")
import math
print("before functionA")
def functionA():
print("Function A")
print("before functionB")
def functionB():
print("Function B {}".format(math.sqrt(100)))
print("before __name__ guard")
if __name__ == '__main__':
functionA()
functionB()
print("after __name__ guard")
Специальные переменные
Когда интерпретатор Python читает исходный файл, он сначала определяет несколько специальных переменных. В этом случае нас интересует переменная __name__
.
Когда ваш модуль является основной программой
Если вы запускаете свой модуль (исходный файл) в качестве основной программы, например
python foo.py
интерпретатор назначит жестко запрограммированную строку "__main__"
переменной __name__
, т. е.
# It's as if the interpreter inserts this at the top
# of your module when run as the main program.
__name__ = "__main__"
Когда ваш модуль импортирован другим
С другой стороны, предположим, что основной программой является какой-то другой модуль, который импортирует ваш модуль. Это означает, что в основной программе или в каком-либо другом модуле, импортируемом основной программой, есть такой оператор:
# Suppose this is in some other main program.
import foo
Интерпретатор будет искать ваш foo.py
файл (наряду с поиском нескольких других вариантов) и перед выполнением этого модуля присвоит переменной __name__
имя "foo"
из оператора импорта, т. Е.
# It's as if the interpreter inserts this at the top
# of your module when it's imported from another module.
__name__ = "foo"
Выполнение кода модуля
После установки специальных переменных интерпретатор выполняет весь код в модуле, по одной инструкции за раз. Вы можете открыть другое окно сбоку с образцом кода, чтобы вы могли следовать этому объяснению.
Всегда
Он печатает строку "before import"
(без кавычек).
Он загружает модуль math
и назначает его переменной с именем math
. Это эквивалентно замене import math
следующим (обратите внимание, что __import__
- это функция низкого уровня в Python, которая принимает строку и запускает фактический импорт):
# Find and load a module given its string name, "math",
# then assign it to a local variable called math.
math = __import__("math")
Он печатает строку "before functionA"
.
Он выполняет блок def
, создает объект функции, а затем назначает этот объект функции переменной с именем functionA
.
Он печатает строку "before functionB"
.
Он выполняет второй блок def
, создавая другой объект функции, а затем присваивая его переменной с именем functionB
.
Он печатает строку "before __name__ guard"
.
Только тогда, когда ваш модуль является основной программой
- Если ваш модуль является основной программой, он увидит, что
__name__
действительно установлен на "__main__"
, и вызовет две функции, распечатав строки "Function A"
и "Function B 10.0"
.
Только когда ваш модуль импортирован другим
- (Вместо этого). Если ваш модуль не является основной программой, но был импортирован другой программой, тогда
__name__
будет "foo"
, а не "__main__"
, и он пропустит тело оператора if
.
Всегда
- В обоих случаях он напечатает строку
"after __name__ guard"
.
Резюме
Таким образом, вот что будет напечатано в двух случаях:
# What gets printed if foo is the main program
before import
before functionA
before functionB
before __name__ guard
Function A
Function B 10.0
after __name__ guard
# What gets printed if foo is imported as a regular module
before import
before functionA
before functionB
before __name__ guard
after __name__ guard
Почему это так работает?
Вы, естественно, можете задаться вопросом, зачем кому-то это нужно. Ну, иногда вы хотите написать .py
файл, который может использоваться другими программами и / или модулями как модуль, а также может запускаться как сама основная программа. Примеры:
Ваш модуль представляет собой библиотеку, но вы хотите иметь режим сценария, в котором он запускает некоторые модульные тесты или демонстрацию.
Ваш модуль используется только как основная программа, но в нем есть несколько модульных тестов, а среда тестирования работает, импортируя .py
файлы, такие как ваш скрипт, и запускает специальные тестовые функции. Вы не хотите, чтобы он пытался запустить скрипт только потому, что он импортирует модуль.
Ваш модуль в основном используется как основная программа, но он также предоставляет удобный для программиста API для опытных пользователей.
Помимо этих примеров, элегантно то, что запуск сценария на Python - это просто установка нескольких волшебных переменных и импорт сценария. Запуск сценария - это побочный эффект импорта модуля сценария.
Пища для размышлений
Вопрос: Могу ли я иметь несколько __name__
проверочных блоков? Ответ: это странно, но язык вас не остановит.
Предположим, следующее находится в foo2.py
. Что произойдет, если вы скажете python foo2.py
в командной строке? Почему?
# Suppose this is foo2.py.
import os, sys; sys.path.insert(0, os.path.dirname(__file__)) # needed for some interpreters
def functionA():
print("a1")
from foo2 import functionB
print("a2")
functionB()
print("a3")
def functionB():
print("b")
print("t1")
if __name__ == "__main__":
print("m1")
functionA()
print("m2")
print("t2")
- Теперь выясните, что произойдет, если вы уберете
__name__
проверку в foo3.py
:
# Suppose this is foo3.py.
import os, sys; sys.path.insert(0, os.path.dirname(__file__)) # needed for some interpreters
def functionA():
print("a1")
from foo3 import functionB
print("a2")
functionB()
print("a3")
def functionB():
print("b")
print("t1")
print("m1")
functionA()
print("m2")
print("t2")
- Что это будет делать при использовании в качестве сценария? При импорте в виде модуля?
# Suppose this is in foo4.py
__name__ = "__main__"
def bar():
print("bar")
print("before __name__ guard")
if __name__ == "__main__":
bar()
print("after __name__ guard")
person
Mr Fooz
schedule
07.01.2009