Почему использовать def main()?
Вопрос по Python: Зачем использовать конструкцию if __name__ == "__main__":
?
Я просмотрел несколько примеров кода и учебных материалов, где используется следующий шаблон:
def main():
# мой код здесь
if __name__ == "__main__":
main()
Но в чем же дело? Есть ли какие-то причины не определять функции вверху файла и просто писать код под ними? Например:
def my_function():
# мой код здесь
def my_function_two():
# мой код здесь
# какой-то код
# вызов функции
# print(что-то)
Мне просто интересно, есть ли какой-то смысл в использовании main
? Почему это считается хорошей практикой?
4 ответ(ов)
Без основного стража (main sentinel) код будет выполнен даже если скрипт будет импортирован как модуль. Это может привести к нежелательным побочным эффектам, таким как исполнение кода инициализации или запуск тестов, когда вы просто хотите использовать функции и классы из этого модуля. Основной страж, который проверяет, является ли файл исполняемым, пригоден для предотвращения выполнения такого кода при импорте. Обычно это выражается в следующем виде:
if __name__ == "__main__":
# Код, который должен выполняться только при запуске файла как основного скрипта
Если это условие не присутствует, то при каждом импорте модуля будет выполняться весь код, находящийся вне функций или классов, что может нарушить логику приложения.
Хотя другие уже ответили на этот вопрос, я думаю, у меня есть что добавить.
Вот несколько причин, почему стоит использовать условие if
, вызывающее main()
(в произвольном порядке):
- В других языках (например, C и Java) есть функция
main()
, которая вызывается при выполнении программы. Используя этотif
, мы можем сделать так, чтобы Python вёл себя аналогично, что будет более привычно для многих людей. - Код станет чище, легче читаемым и лучше организованным. (Да, я понимаю, что это субъективно).
- Это позволит
import
этот код Python как модуль без неприятных побочных эффектов. - Это даст возможность запускать тесты на этом коде.
- Это позволит импортировать код в интерактивную оболочку Python и тестировать/отлаживать/запускать его.
- Переменные внутри
def main
являются локальными, в то время как те, что снаружи — глобальными. Это может привести к неожиданным ошибкам и поведению.
Однако вы не обязаны писать функцию main()
и вызывать её внутри условия if
.
Лично я обычно начинаю писать небольшие скрипты без каких-либо функций. Если скрипт становится достаточно большим или я чувствую, что помещать весь код в функцию было бы полезно, я рефакторю его и делаю это. То же самое происходит, когда я пишу скрипты на bash
.
Даже если вы поместите код внутри функции main
, никто не требует делать это именно так. Есть аккуратный вариант:
import sys
def main(argv):
# Мой код здесь
pass
if __name__ == "__main__":
main(sys.argv)
Это позволяет вызывать main()
из других скриптов (или из интерактивной оболочки), передавая настраиваемые параметры. Это может быть полезно в юнит-тестах или при пакетной обработке. Но помните, что приведённый выше код требует парсинга argv
, так что, возможно, лучше использовать другой вызов, который будет передавать уже разобранные параметры.
В объектно-ориентированном приложении, которое я написал, код выглядел так:
class MyApplication(something):
# Мой код здесь
if __name__ == "__main__":
app = MyApplication()
app.run()
Так что не стесняйтесь писать код так, как вам удобнее. 😃
Файл foo.py
можно использовать двумя способами.
Импорт в другой файл:
import foo
В этом случае значение
__name__
будет равноfoo
, и код в условииif __name__ == '__main__':
не выполнится, поэтомуXXXX
не будет напечатано.Прямое выполнение:
python foo.py
Когда файл выполняется напрямую, значение
__name__
становится равным__main__
, и код в секцииif
выполняется, в результате чего будет напечатаноXXXX
.
Одно из применений этой функциональности — написание различных модульных тестов внутри одного и того же модуля.
Если вы рассматриваете второй скрипт, то при его импорте в другой скрипт инструкции, находящиеся на "глобальном уровне", будут выполнены. Это поведение связано с тем, что при импорте модуля Python исполняет весь код на верхнем уровне этого модуля, что может привести к нежелательным эффектам, если вы не учитываете этот момент. Поэтому рекомендуется помещать код, который не должен выполняться при импорте, внутрь конструкции if __name__ == "__main__":
. Это позволит вам контролировать, что именно будет исполняться при прямом запуске скрипта или его импорте.
Как клонировать список, чтобы он не изменялся неожиданно после присваивания?
Преобразование списка словарей в DataFrame pandas
Ошибка: "'dict' объект не имеет метода 'iteritems'"
Как явно освободить память в Python?
Выбор строки из pandas Series/DataFrame по целочисленному индексу