[Python] Что делать, если __name__ == "__main__": делать?


Answers

Когда ваш скрипт запускается, передавая его как команду интерпретатору Python,

python myscript.py

весь код, который находится на уровне отступа 0, выполняется. Определенные функции и классы определены, но не определены, но ни один из их кодов не запускается. В отличие от других языков, функция main() не запускается автоматически - функция main() неявно содержит весь код на верхнем уровне.

В этом случае код верхнего уровня является блоком if . __name__ - встроенная переменная, которая оценивает имя текущего модуля. Однако, если модуль запускается напрямую (как в myscript.py выше), тогда вместо __name__ устанавливается строка "__main__" . Таким образом, вы можете проверить, запускается ли ваш скрипт напрямую или что-то другое путем тестирования

if __name__ == "__main__":
    ...

Если ваш скрипт импортируется в другой модуль, его различные определения функций и классов будут импортированы, а его код верхнего уровня будет выполнен, но код в том-токе вышеприведенного предложения if не будет запущен как условие не выполняется. В качестве базового примера рассмотрим следующие два сценария:

# file one.py
def func():
    print("func() in one.py")

print("top-level in one.py")

if __name__ == "__main__":
    print("one.py is being run directly")
else:
    print("one.py is being imported into another module")
# file two.py
import one

print("top-level in two.py")
one.func()

if __name__ == "__main__":
    print("two.py is being run directly")
else:
    print("two.py is being imported into another module")

Теперь, если вы вызываете интерпретатора как

python one.py

Выход будет

top-level in one.py
one.py is being run directly

Если вместо этого вы запустите two.py :

python two.py

Вы получаете

top-level in one.py
one.py is being imported into another module
top-level in two.py
func() in one.py
two.py is being run directly

Таким образом, когда модуль загружается, его __name__ равно "one" вместо "__main__" .

Question

Что делает if __name__ == "__main__": делать?

# Threading example
import time, thread

def myfunction(string, sleeptime, lock, *args):
    while True:
        lock.acquire()
        time.sleep(sleeptime)
        lock.release()
        time.sleep(sleeptime)

if __name__ == "__main__":
    lock = thread.allocate_lock()
    thread.start_new_thread(myfunction, ("Thread #: 1", 2, lock))
    thread.start_new_thread(myfunction, ("Thread #: 2", 2, lock))



если имя == ' main ':

Мы видим, что __name__ == '__main__' : довольно часто.

Он проверяет, импортирован ли модуль или нет.

Другими словами, код внутри блока if будет выполняться только при прямом запуске кода. Здесь directly означает not imported .

Давайте посмотрим, что он делает, используя простой код, который печатает имя модуля:

# test.py
def test():
   print('test module name=%s' %(__name__))

if __name__ == '__main__':
   print('call test()')
   test()

Если мы запускаем код напрямую через python test.py , имя модуля __main__ :

call test()
test module name=__main__



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

if __name__ == '__main__':
    # Do something appropriate here, like calling a
    # main() function defined elsewhere in this module.
    main()
else:
    # Do nothing. This module has been imported by another
    # module that wants to make use of the functions,
    # classes and other useful bits it has defined.



Здесь много разных механизмов механики рассматриваемого кода, «Как», но для меня это не имело смысла, пока я не понял «Почему». Это должно быть особенно полезно для новых программистов.

Возьмите файл «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() ; ok, печать « периферийная задача: может быть полезна в других проектах ».
  • Что это? Оператор if . Ну, условие выполнено (переменная __name__ установлена ​​на "__main__" ), поэтому я буду вводить функцию main() и печатать « главную функцию: это то, где действие ».

Нижние две строки означают: «Если это main или« домашний »сценарий, выполните функцию main() ». Вот почему вы увидите def main(): block up top, который содержит основной поток функций скрипта.

Зачем это реализовать?

Помните, что я сказал ранее о заявках на импорт? При импорте модуля он не просто «распознает» его и ждет дальнейших инструкций - он фактически выполняет все исполняемые операции, содержащиеся в скрипте. Таким образом, добавление мяса вашего скрипта в функцию main() эффективно помещает его в карантин, изолируя его, чтобы он не сразу запускался при импорте с помощью другого скрипта.

Опять же, будут исключения, но обычной практикой является то, что main() обычно не называется вызываемым извне. Поэтому вам может быть интересно еще одно: если мы не вызываем main() , почему мы вообще вызываем сценарий? Это потому, что многие люди строят свои скрипты с автономными функциями, которые создаются для запуска независимо от остальной части кода в файле. Затем их позже называют в другом месте в тексте сценария. Это подводит меня к этому:

Но код работает без него

Да все верно. Эти отдельные функции можно вызывать из встроенного сценария, который не содержится внутри функции main() . Если вы привыкли (как и я, на ранних этапах программирования) к созданию встроенных сценариев, которые делают именно то, что вам нужно, и вы попытаетесь выяснить это снова, если вам понадобится эта операция снова. ну, вы не привыкли к такой внутренней структуре вашего кода, потому что его сложнее строить, и это не так просто интуитивно понятно. Но это сценарий, который, вероятно, не может иметь свои функции, вызванные извне, потому что если он это сделал, он сразу же начнет вычислять и присваивать переменные. И, скорее всего, если вы пытаетесь повторно использовать функцию, ваш новый сценарий тесно связан с старым, что будут конфликтующие переменные.

Разделяя независимые функции, вы получаете возможность повторно использовать свою предыдущую работу, вызвав их в другой скрипт. Например, «example.py» может импортировать «xy.py» и вызвать x() , используя функцию «x» из «xy.py». (Возможно, это заглавное 3-е слово данной текстовой строки, создание массива numpy из списка чисел и возведение в квадрат их или деление 3D-поверхности. Возможности безграничны).

[В стороне, этот поток содержит ответ от @kindall, который, наконец, помог мне понять - почему, а не как. К сожалению, это было отмечено как дубликат этого , что я считаю ошибкой.]




if __name__ == "__main__": это, в основном, среда сценария верхнего уровня, она указывает интерпретатор, который («У меня есть наивысший приоритет, который нужно выполнить первым»).

'__main__' - это имя области, в которой выполняется код верхнего уровня. Значение __name__ модуля устанавливается равным '__main__' при чтении со стандартного ввода, сценария или из интерактивного приглашения.

if __name__ == "__main__":
    # execute only if run as a script
    main()



Что делать, if __name__ == "__main__": делать?

__name__ - это глобальная переменная (в Python, глобальная на самом деле означает на уровне модуля ), которая существует во всех пространствах имен. Обычно это имя модуля (как тип str ).

Однако, как единственный частный случай, в любом запущенном процессе Python, как и в mycode.py:

python mycode.py

в противном случае анонимное глобальное пространство имен присваивается значению '__main__' его __name__ .

Таким образом, включая финальные строки

if __name__ == '__main__':
    main()
  • в конце вашего сценария mycode.py,
  • когда он является основным модулем начальной точки, который запускается процессом Python,

приведет к выполнению уникальной main функции вашего скрипта.

Еще одно преимущество использования этой конструкции: вы также можете импортировать свой код в качестве модуля в другой скрипт, а затем запустить основную функцию, если и когда ваша программа решит:

import mycode
# ... any amount of other code
mycode.main()



Вы можете сделать файл полезным как скрипт, так и импортируемый модуль .

fibo.py (модуль с именем fibo )

# Other modules can IMPORT this MODULE to use the function fib
def fib(n):    # write Fibonacci series up to n
    a, b = 0, 1
    while b < n:
        print(b, end=' ')
        a, b = b, a+b
    print()

# This allows the file to be used as a SCRIPT
if __name__ == "__main__":
    import sys
    fib(int(sys.argv[1]))

Ссылка: https://docs.python.org/3.5/tutorial/modules.html




if __name__ == "__main__":
    main()

Проверяет, является ли атрибут __name__ сценария python "__main__" . Другими словами, если сама программа выполнена, атрибут будет __main__ , поэтому программа будет выполнена (в этом случае функция main() ).

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




Что делает if __name__ == "__main__": делать?

Чтобы описать основы:

  • Глобальная переменная __name__ в модуле, являющемся точкой входа в вашу программу, является '__main__' . В противном случае это имя, в которое вы импортируете модуль.

  • Таким образом, код в блоке if будет выполняться только в том случае, если модуль является точкой входа в вашу программу.

  • Он позволяет импортировать код в модуле другими модулями, не выполняя блок кода под импортом.

Зачем нам это надо?

Разработка и тестирование вашего кода

Предположим, вы пишете скрипт Python, предназначенный для использования в качестве модуля:

def do_important():
    """This function does something very important"""

Вы можете протестировать модуль, добавив этот вызов функции в нижнюю часть:

do_important()

и запускать его (в командной строке) с чем-то вроде:

~$ python important.py

Проблема

Однако, если вы хотите импортировать модуль в другой скрипт:

import important

При импорте будет do_important функция do_important , поэтому вы, вероятно, прокомментируете свой вызов функции do_important() внизу.

# do_important() # I must remember to uncomment to execute this!

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

Лучший способ

Переменная __name__ указывает на пространство имен где бы ни находился интерпретатор Python.

Внутри импортированного модуля это имя этого модуля.

Но внутри первичного модуля (или интерактивного сеанса Python, т. Е. Read, Eval, Print Loop или REPL) интерпретатора вы запускаете все из своего "__main__" .

Поэтому, если вы проверяете перед выполнением:

if __name__ == "__main__":
    do_important()

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

Еще лучший способ

Тем не менее, есть возможность использовать Pythonic для улучшения этого.

Что делать, если мы хотим запустить этот бизнес-процесс извне модуля?

Если мы поместим код, который хотим реализовать, когда мы разрабатываем и тестируем в такой функции, а затем делаем нашу проверку для '__main__' сразу после:

def main():
    """business logic for when running this module as the primary one!"""
    setup()
    foo = do_important()
    bar = do_even_more_important(foo)
    for baz in bar:
        do_super_important(baz)
    teardown()

# Here's our payoff idiom!
if __name__ == '__main__':
    main()

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

Это позволит модулю и его функциям и классам импортироваться в другие сценарии без запуска main функции, а также позволяет вызывать модуль (и его функции и классы) при работе из другого модуля '__main__' , т. Е.

import important
important.main()

Эта идиома также может быть найдена в документации Python в объяснении модуля __main__ . Этот текст гласит:

Этот модуль представляет собой (в противном случае анонимную) область, в которой выполняется основная программа интерпретатора - команды, считываемые либо из стандартного ввода, либо из файла сценария, либо из интерактивного приглашения. Именно эта среда, в которой идиоматическая сцена «условный сценарий» заставляет сценарий запускаться:

if __name__ == '__main__':
    main()



Прежде чем объяснять что-либо о if __name__ == '__main__' важно понять, что такое __name__ и что он делает.

Что такое __name__ ?

__name__ - это DunderAlias ​​- можно рассматривать как глобальную переменную (доступную из модулей) и работает аналогично global .

Это строка (глобальная, как упоминалось выше), как указано type(__name__) (дает <class 'str'> ), и является встроенным стандартом для версий Python 3 и Python 2 .

Где:

Его можно использовать не только в скриптах, но также можно найти как в интерпретаторе, так и в модулях / пакетах.

Переводчик:

>>> print(__name__)
__main__
>>>

Автор сценария:

test_file.py :

print(__name__)

Результат в __main__

Модуль или пакет:

somefile.py:

def somefunction():
    print(__name__)

test_file.py:

import somefile
somefile.somefunction()

Результат в somefile

Обратите внимание, что при использовании в пакете или модуле __name__ принимает имя файла. Путь фактического пути модуля или пакета не указан, но имеет свой собственный DunderAlias __file__ , который позволяет это.

Вы должны увидеть, что где __name__ , где это основной файл (или программа), всегда будет возвращать __main__ , а если это модуль / пакет или что-то, что запущено с каким-либо другим скриптом Python, вернет имя файла откуда оно возникло.

Практика:

Быть переменной означает, что ее значение может быть перезаписано («can» не означает «should»), перезаписывая значение __name__ приведет к отсутствию читаемости. Поэтому не делайте этого по любой причине. Если вам нужна переменная, определите новую переменную.

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

пример:

>>> __name__ = 'Horrify' # Change default from __main__
>>> if __name__ == 'Horrify': print(__name__)
...
>>> else: print('Not Horrify')
...
Horrify
>>>

В целом считается хорошей практикой включать в скрипты if __name__ == '__main__' .

Теперь ответьте, if __name__ == '__main__' :

Теперь мы знаем, что поведение __name__ становится понятным:

if это оператор управления потоком, содержащий блок кода, будет выполняться, если заданное значение истинно. Мы видели, что __name__ может принимать либо __main__ либо имя файла, из которого он был импортирован.

Это означает, что если __name__ равно __main__ то файл должен быть основным файлом и должен быть запущен (или это интерпретатор), а не модуль или пакет, импортированные в скрипт.

Если действительно __name__ принимает значение __main__ то все, что находится в этом блоке кода, будет выполняться.

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

Модули:

__name__ также может использоваться в модулях для определения имени модуля

Варианты:

Также можно использовать другие, менее распространенные, но полезные вещи с __name__ , некоторые из которых я покажу здесь:

Выполнение только в том случае, если файл является модулем или пакетом:

if __name__ != '__main__':
    # Do some useful things 

Выполнение одного условия, если файл является основным, а другой, если это не так:

if __name__ == '__main__':
    # Execute something
else:
    # Do some useful things

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

Он также позволяет запускать модули из командной строки в качестве основных сценариев, что также может быть очень полезно.




Существует ряд переменных, которые система (интерпретатор Python) предоставляет исходные файлы (модули). Вы можете получить их значения в любое время, поэтому, давайте сосредоточимся на переменной __name__ variable / attribute:

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

Однако прежде чем интерпретатор выполнит файл исходного кода, он определяет несколько специальных переменных для этого файла; __name__ - одна из тех специальных переменных, которые Python автоматически определяет для каждого файла исходного кода.

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

Если это импортируется из другого модуля, то __name__ будет установлено имя этого модуля.

Итак, в вашем примере отчасти:

if __name__ == "__main__":
   lock = thread.allocate_lock()
   thread.start_new_thread(myfunction, ("Thread #: 1", 2, lock))
   thread.start_new_thread(myfunction, ("Thread #: 2", 2, lock))

означает, что блок кода:

lock = thread.allocate_lock()
thread.start_new_thread(myfunction, ("Thread #: 1", 2, lock))
thread.start_new_thread(myfunction, ("Thread #: 2", 2, lock))

будет выполняться только при непосредственном запуске модуля; блок кода не будет выполняться, если другой модуль вызывает / импортирует его, потому что значение __name__ не будет равно « main » в этом конкретном экземпляре.

Надеюсь, это поможет.




Links