Существует множество различных подходов к механике рассматриваемого кода, «как», но для меня ничего из этого не имело смысла, пока я не понял «почему». Это должно быть особенно полезно для новых программистов.
Взять файл "ab.py":
def a():
print('A function in ab file');
a()
И второй файл "xy.py":
import ab
def main():
print('main function: this is where the action is')
def x():
print ('peripheral task: might be useful in other projects')
x()
if __name__ == "__main__":
main()
Что на самом деле делает этот код?
Когда вы выполняете xy.py
, вы import ab
. Оператор import сразу же запускает модуль при импорте, поэтому операции ab
выполняются раньше, чем до xy
. Закончив с ab
, он продолжает с xy
.
Интерпретатор отслеживает, какие сценарии выполняются с __name__
. Когда вы запускаете скрипт - независимо от того, как вы его назвали - интерпретатор называет его "__main__"
, делая его основным или «домашним» скриптом, к которому возвращается после запуска внешнего скрипта.
Любой другой скрипт, который вызывается из этого "__main__"
скрипта, получает имя файла как __name__
(например, __name__ == "ab.py"
). Следовательно, строка if __name__ == "__main__":
является тестом интерпретатора, чтобы определить, интерпретирует ли он / анализирует «домашний» сценарий, который был первоначально выполнен, или он временно просматривает другой (внешний) сценарий. Это дает программисту гибкость, позволяющую сценарию вести себя по-разному, если он выполняется напрямую или вызывается извне.
Давайте пройдемся по приведенному выше коду, чтобы понять, что происходит, сосредоточив внимание в первую очередь на не заштрихованных строках и порядке их появления в скриптах. Помните, что функциональные блоки - или def
- сами по себе ничего не делают, пока их не вызовут. Что может сказать переводчик, пробормотав про себя:
- Откройте xy.py в качестве домашнего файла; назовите его
"__main__"
в переменной __name__
.
- Импорт и открытие файла с
__name__ == "ab.py"
.
- О, функция. Я запомню это.
- Хорошо, функция
a()
; Я только что узнал это. Печать ' Функция в файле ab '.
- Конец файла; вернуться к
"__main__"
!
- О, функция. Я запомню это.
- Еще один.
- Функция
x()
; ок, печать ' периферийное задание: может быть полезно в других проектах '.
- Что это?
if
заявление. Итак, условие выполнено (переменная __name__
была установлена на "__main__"
), поэтому я войду в функцию main()
и выведу основную функцию : здесь действие .
Две нижние строки означают: «Если это скрипт "__main__"
или« home », выполните функцию с именем main()
». Вот почему вы увидите блок def main():
вверху, который содержит основной поток функций скрипта.
Зачем это реализовывать?
Помните, что я говорил ранее об операциях импорта? Когда вы импортируете модуль, он не просто «распознает» его и ждет дальнейших инструкций - он фактически выполняет все исполняемые операции, содержащиеся в скрипте. Таким образом, помещение текста вашего скрипта в функцию main()
эффективно помещает его в карантин, изолируя его, чтобы он не запустился сразу после импорта другим скриптом.
Опять же, будут исключения, но обычная практика заключается в том, что main()
обычно не вызывается извне. Так что вам может быть интересно еще одно: если мы не вызываем main()
, почему мы вообще вызываем скрипт? Это связано с тем, что многие люди структурируют свои скрипты с помощью автономных функций, которые создаются для запуска независимо от остальной части кода в файле. Затем они позже вызваны где-то еще в теле сценария. Что подводит меня к этому:
Но код работает без него
Да, все верно. Эти отдельные функции можно вызывать из встроенного скрипта, который не содержится внутри функции main()
. Если вы привыкли (как и я, на ранних этапах обучения программированию) к созданию встроенных сценариев, которые выполняют именно то, что вам нужно, и вы попытаетесь снова это выяснить, если вам когда-нибудь понадобится эта операция снова ... ... ну, вы не привыкли к такого рода внутренней структуре своего кода, потому что его сложнее построить и он не настолько интуитивно понятен.
Но это сценарий, который, вероятно, не может вызывать свои функции извне, потому что если он это сделает, он сразу же начнет вычислять и присваивать переменные. И есть вероятность, что если вы пытаетесь повторно использовать функцию, ваш новый скрипт достаточно тесно связан со старым, что будут конфликтующие переменные.
Разделяя независимые функции, вы получаете возможность повторно использовать вашу предыдущую работу, вызывая их в другой скрипт. Например, «example.py» может импортировать «xy.py» и вызывать x()
, используя функцию «x» из «xy.py». (Возможно, это заглавная буква третьего слова данной текстовой строки; создание массива NumPy из списка чисел и возведение их в квадрат; или растяжение трехмерной поверхности. Возможности безграничны.)
(Кроме того, этот вопрос содержит ответ @kindall, который наконец помог мне понять - почему, а не как. К сожалению, он был помечен как дубликат этого , что я считаю ошибкой.)