Що робити, якщо __name__ == "__main__": зробити?


6059

З огляду на наступний код, що 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))

Чи if __name__ == "__main__":застарілий / застарілий стан блоку на Python 3? Я знайшов деяку інформацію, яка говорить про це.
carloswm85

1
@ carloswm85 Це неправда.
Giorgos Myrianthous

Відповіді:


6639

Щоразу, коли інтерпретатор 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файл (разом з пошуком кількох інших варіантів), і перед виконанням цього модуля він призначить ім'я "foo"з оператора імпорту __name__змінної, тобто

# It's as if the interpreter inserts this at the top
# of your module when it's imported from another module.
__name__ = "foo"

Виконання коду модуля

Після встановлення спеціальних змінних інтерпретатор виконує весь код у модулі, по одному оператору за один раз. Можливо, ви захочете відкрити ще одне вікно збоку з зразком коду, щоб ви могли дотримуватися цього пояснення.

Завжди

  1. Він друкує рядок "before import"(без лапок).

  2. Він завантажує 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")
  1. Він друкує рядок "before functionA".

  2. Він виконує defблок, створюючи об’єкт функції, а потім присвоює цьому об'єкту функції змінну, що називається functionA.

  3. Він друкує рядок "before functionB".

  4. Він виконує другий defблок, створюючи інший об’єкт функції, а потім присвоює йому змінну, що називається functionB.

  5. Він друкує рядок "before __name__ guard".

Тільки тоді, коли ваш модуль є основною програмою

  1. Якщо ваш модуль є основною програмою, він побачить, що __name__було дійсно встановлено, "__main__"і він викликає дві функції, друкуючи рядки "Function A"та "Function B 10.0".

Тільки тоді, коли ваш модуль імпортується іншим

  1. ( натомість ) Якщо ваш модуль не є основною програмою, але був імпортований іншою, то __name__буде "foo", ні "__main__", і він пропустить тіло ifоператора.

Завжди

  1. Він надрукує рядок "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.

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.

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")

14
З цікавості: Що трапляється, якщо я запускаю subprocess.run('foo_bar.py')сценарій python? Я припускаю, що foo_barце розпочнеться так __name__ = '__main__'само, як коли я foo_bar.pyвручну вкажу в cmd. Це так? Враховуючи відповідь @MrFooz, у цьому не повинно виникнути жодних проблем і мати стільки "основних" модулів, скільки мені подобається. Навіть зміна __name__значення або наявність декількох незалежно створює екземплярів (або екземплярів, які створювали один одного subprocess) взаємодіють між собою, має бути ділом, як зазвичай для Python. Я щось сумую?
Гаджеф

12
@hajef Ви вірно розумієте, як би все працювало subprocess.run. Тим не менш, загально кращим способом спільного використання коду між скриптами є створення модулів і змушення скриптів викликати спільні модулі, а не викликати один одного як сценарії. Важко налагоджувати subprocess.runвиклики, оскільки більшість налагоджувачів не перескакують межі процесу, це може додати нетривіальну накладну систему для створення та знищення зайвих процесів тощо.
Містер Фооз,

4
У мене є сумніви в прикладі foo2.py в розділі «Їжа для роздумів». Що робить функція імпорту foo2.pyB? На мій погляд, він просто імпортує foo2.py з functionB
user471651

1
@MrFooz Я ніколи не збирався робити щось подібне до цього xD Це мені просто прийшло в голову, і я зрозумів, що дивно хотілося б, можливо, допомогти ppl. обертаючи їх розум навколо подібного роду речі. @ user471651 Чому слід from foo2 import functionBімпортувати foo2 з functionB? Це смислове викривлення. from module import methodімпортує метод з модуля.
Гаджеф

2
Одним із модулів, які можуть імпортувати ваш код, є multiprocessing, зокрема, зробити цей тест необхідним у Windows.
Ян Верньє

1801

Коли ваш сценарій запускається, передаючи його як команду інтерпретатору 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

Таким чином, коли модуль oneзавантажується, він __name__дорівнює "one"замість "__main__".


Чудова відповідь, це була найясніша відповідь на мою думку. +1!
TheTechRobo36414519

+1 для такого способу роздуму над цим: перший відрізковий рядок запускається лише спочатку, поки ви не запустите функції на цьому першому рядку
Ілля Мок

719

Найпростішим поясненням __name__змінної (imho) є наступне:

Створіть такі файли.

# a.py
import b

і

# b.py
print "Hello World from %s!" % __name__

if __name__ == '__main__':
    print "Hello World again from %s!" % __name__

Запустивши їх, ви отримаєте цей результат:

$ python a.py
Hello World from b!

Як бачите, коли імпортується модуль, Python встановлює globals()['__name__']в цьому модулі ім'я модуля. Також при імпорті запускається весь код у модулі. Оскільки ifзаява оцінює, Falseця частина не виконується.

$ python b.py
Hello World from __main__!
Hello World again from __main__!

Як ви бачите, коли файл виконується, Python встановлює globals()['__name__']цей файл у "__main__". Цього разу ifзаява оцінюється Trueта виконується.


513

Що робить 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() # I must remember to uncomment to execute this!

І тоді вам доведеться запам'ятати, чи ви прокоментували виклик тестової функції чи ні. І ця додаткова складність означатиме, що ви, ймовірно, забудете, зробивши процес розробки більш клопітким.

Кращий шлях

В __name__точки змінних в просторі імен , де інтерпретатор Python , трапляється в даний момент.

Всередині імпортного модуля - це ім'я цього модуля.

Але всередині основного модуля (або інтерактивного сеансу Python, тобто Read, Eval, Print Loop чи REPL) інтерпретатора, ви запускаєте все з нього "__main__".

Тож якщо ви перевірите перед виконанням:

if __name__ == "__main__":
    do_important()

З урахуванням вищесказаного ваш код буде виконуватися лише тоді, коли ви запускаєте його як основний модуль (або навмисно викликаєте його з іншого сценарію).

Ще кращий шлях

Однак є пітонічний спосіб покращити це.

Що робити, якщо ми хочемо запустити цей бізнес-процес поза модулем?

Якщо ми ставимо код, який ми хочемо виконувати, коли ми розробляємо і тестуємо в такій функції, а потім робимо перевірку на наявність '__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()

125

if __name__ == "__main__"це частина, яка запускається, коли сценарій запускається з (скажімо) командного рядка, використовуючи команду типу python myscript.py.


2
Чому файл, що знаходиться helloworld.pyлише print("hello world")в ньому, може працювати з командою, python helloworld.pyнавіть коли його немає if __name__ == "__main__"?
hi15

83

Що робить if __name__ == "__main__":?

__name__є глобальною змінною (в Python, global фактично означає на рівні модуля ), що існує у всіх просторах імен. Зазвичай це ім'я модуля (як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()

72

Тут є багато різних питань щодо механіки коду, про який йдеться, "Як", але для мене це не мало сенсу, поки я не зрозумів "Чому". Це має бути особливо корисним для нових програмістів.

Візьміть файл "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. Оператор імпорту запускає модуль негайно при імпорті, тому abоперації виконуються до залишку xy's. Після закінчення роботи 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__"сценарій або 'домашній', виконайте функцію, яку називають main()". Ось чому ви побачите def main():блок вгорі, який містить основний потік функціональності сценарію.

Навіщо це реалізовувати?

Пам'ятаєте, що я казав раніше про імпортні заяви? При імпорті модуля він не просто "розпізнає" його і чекає подальших інструкцій - він фактично виконує всі виконувані операції, що містяться в скрипті. Отже, введення м'яса вашого сценарію у main()функцію ефективно карантинує його, ставлячи його в ізоляцію, щоб воно не було негайно запущено при імпорті іншого сценарію.

Знову ж таки, будуть винятки, але звичайна практика полягає в тому, main()що зазвичай не викликають зовнішню позицію. Тож вам може бути цікаво ще одне: якщо ми не дзвонимо main(), чому ми взагалі викликаємо сценарій? Це тому, що багато людей структурують свої сценарії за допомогою самостійних функцій, створених для запуску незалежно від решти коду у файлі. Потім вони потім називаються десь в тілі сценарію. Що підводить мене до цього:

Але код працює без нього

Так, правильно. Ці окремі функції можна викликати з вбудованого сценарію, який не міститься всередині main()функції. Якщо ви звикли (як і я, на своїх ранніх етапах програмування) будувати вбудовані сценарії, які виконують саме те, що вам потрібно, і ви спробуєте це знову зрозуміти, якщо вам знову потрібна ця операція .. добре, ви не звикли до такої внутрішньої структури свого коду, оскільки це складніше будувати і читати не так інтуїтивно.

Але це сценарій, який, ймовірно, не може мати свої функції, викликані зовні, тому що, якби це зробив, він негайно почав би обчислювати та призначити змінні. І швидше за все, якщо ви намагаєтесь повторно використовувати функцію, ваш новий скрипт досить тісно пов'язаний зі старим, що будуть конфліктуючі змінні.

Розділяючи незалежні функції, ви отримуєте можливість повторно використовувати попередню роботу, викликаючи їх в інший сценарій. Наприклад, "example.py" може імпортувати "xy.py" та викликати x(), використовуючи функцію "x" з "xy.py". (Можливо, це використання великої літери третього слова заданого текстового рядка; створення масиву NumPy зі списку чисел та їх порівняння; або зменшення тривимірної поверхні. Можливості безмежні.)

(Вбік цього запитання містить відповідь від @kindall, яка нарешті допомогла мені зрозуміти - чому, а не як. На жаль, це було позначено як дублікат цього , що, на мою думку, є помилкою.)


52

Коли в нашому модулі є певні висловлювання ( M.py), які ми хочемо виконати, коли він буде запущений як основний (не імпортований), ми можемо розмістити ці оператори (тестові випадки, друковані заяви) під цим ifблоком.

Як за замовчуванням (коли модуль працює як основний, а не імпортований) __name__змінна встановлюється "__main__", а коли вона буде імпортована, __name__змінна отримає інше значення, швидше за все, ім'я модуля ( 'M'). Це корисно для спільного запуску різних варіантів модулів та розділення їх конкретних операторів вводу та виводу, а також, якщо є якісь тестові випадки.

Коротше кажучи , використовуйте цей if __name__ == "main"блок ' ' для запобігання запуску (певного) коду під час імпорту модуля.


43

Простіше кажучи, __name__це змінна, визначена для кожного сценарію, яка визначає, чи виконується сценарій як основний модуль чи він запускається як імпортний модуль.

Отже, якщо у нас є два сценарії;

#script1.py
print "Script 1's name: {}".format(__name__)

і

#script2.py
import script1
print "Script 2's name: {}".format(__name__)

Вихід із виконання script1 є

Script 1's name: __main__

А вихід із виконання script2:

Script1's name is script1
Script 2's name: __main__

Як ти бачиш, __name__ говорить нам, який код є "головним" модулем. Це чудово, тому що ви можете просто писати код і не турбуватися про структурні проблеми, такі як у C / C ++, де, якщо файл не реалізує функцію 'main', він не може бути скомпільований як виконуваний файл, і якщо він є, він не може використовуватися як бібліотека.

Скажімо, ви пишете сценарій Python, який робить щось чудове, і ви реалізуєте судновий набір функцій, корисних для інших цілей. Якщо я хочу їх використовувати, я можу просто імпортувати ваш сценарій і використовувати їх, не виконуючи вашу програму (враховуючи, що ваш код виконується лише в if __name__ == "__main__":контексті). Тоді як у C / C ++ вам доведеться розділити ці фрагменти в окремий модуль, який потім включає файл. Зобразіть ситуацію нижче;

Складний імпорт у С

Стрілки є імпортними посиланнями. Для трьох модулів, кожен з яких намагається включити попередній код модуля, є шість файлів (дев'ять, рахуючи файли реалізації) та п'ять посилань. Це ускладнює включення іншого коду до проекту C, якщо він не складений спеціально як бібліотека. Тепер зображте це для Python:

Елегантний імпорт у Python

Ви пишете модуль, і якщо хтось хоче використовувати ваш код, він просто імпортує його, і __name__змінна може допомогти відокремити виконувану частину програми від частини бібліотеки.


2
Ілюстрація C / C ++ неправильна: 3 рази однакова назва одиниці ( file1 ).
Вовк

40

Давайте розглянемо відповідь більш абстрактно:

Припустимо, у нас цей код є x.py:

...
<Block A>
if __name__ == '__main__':
    <Block B>
...

Блоки А і В запускаються, коли ми бігаємо x.py.

Але просто блок A (а не B) запускається, коли ми запускаємо інший модуль, y.pyнаприклад, в якому x.pyімпортується і код запускається звідти (наприклад, коли функція в x.pyвикликається з y.py).


1
Я не зміг відредагувати публікацію (якщо потрібно змінити мінімум 6 символів). У рядку 14 є "xy", а не "x.py".
завждиНавчання

35

При інтерактивному запуску 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.

34

Поміркуйте:

if __name__ == "__main__":
    main()

Він перевіряє, чи є __name__атрибут сценарію Python "__main__". Іншими словами, якщо програма сама виконується, атрибут буде __main__, тому програма буде виконуватися (у цьому випадкуmain() функція).

Однак якщо ваш скрипт Python використовується модулем, будь-який код за межами ifоператора буде виконаний, тому if \__name__ == "\__main__"він використовується лише для перевірки, чи програма використовується як модуль чи ні, і тому вирішує, чи запускати код.


здається, що надто давно писати світлу відповідь +1
snr

27

Перш ніж пояснити що-небудь 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, поверне ім'я файлу, де він походить від с.

Практика:

Бути змінною означає, що її значення можна перезаписати ("може" не означає "повинно"), замінивши значення__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__речей стає зрозумілішою:

An 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

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

Він також дозволяє запускати модулі з командного рядка як основні сценарії, що також може бути дуже корисно.


25

Я думаю, що найкраще відповісти на глибину та прості слова:

__name__: Кожен модуль в Python має спеціальний атрибут, який називається __name__. Це вбудована змінна, яка повертає назву модуля.

__main__: Як і інші мови програмування, Python також має точку входу в виконання, тобто основну. '__main__' - назва області, у якій виконується код верхнього рівня . В основному у вас є два способи використання модуля Python: Запустіть його безпосередньо як скрипт або імпортуйте його. Коли модуль запускається як сценарій, його __name__встановлюють на __main__.

Таким чином, значення __name__атрибута встановлюється, __main__коли модуль запускається як основна програма. В іншому випадку встановлено значення __name__ , яке містить ім'я модуля.


23

Це особливий варіант, коли викликається файл Python з командного рядка. Зазвичай він використовується для виклику функції "main ()" або виконання іншого відповідного коду запуску, наприклад, обробки аргументів командного рядка.

Це можна було написати декількома способами. Інше:

def some_function_for_instance_main():
    dosomething()


__name__ == '__main__' and some_function_for_instance_main()

Я не кажу, що ви повинні використовувати це у виробничому коді, але він служить для того, щоб продемонструвати, що в цьому немає нічого "магічного" if __name__ == '__main__'. Це хороша умова для виклику основної функції у файлах Python.


7
Я вважаю це поганою формою, оскільки ви 1) покладаєтесь на побічні ефекти та 2) зловживань and. andвикористовується для перевірки того, чи є два булеві твердження правдивими. Оскільки ви не зацікавлені в результаті and, ifзаява чіткіше повідомляє ваші наміри.
jpmc26

8
Залишаючи осторонь питання про те, чи використовувати поведінку короткого замикання булевих операторів як механізм управління потоком - це поганий стиль чи ні, більша проблема полягає в тому, що це зовсім не відповідає на питання .
Марк Амерді

@MarkAmery ха-ха, ше, тепер це так. 😊
професора

19

Існує ряд змінних, які система (інтерпретатор Python) забезпечує вихідними файлами (модулями). Ви можете отримати їх значення в будь-який час, тому зосередимось на змінній / атрибуті __name__ :

Коли 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 " у конкретному екземплярі.

Сподіваюся, це допоможе.


17

if __name__ == "__main__": це в основному середовище сценарію верхнього рівня, і він визначає інтерпретатора, що ("Я маю найвищий пріоритет, який потрібно виконати першим").

'__main__'- назва області, у якій виконується код верхнього рівня. Модуль __name__встановлюється рівним, '__main__'коли він читається зі стандартного вводу, сценарію або з інтерактивного запиту.

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

17

Я читав стільки відповідей на цій сторінці. Я б сказав, якщо ви знаєте річ, напевно ви зрозумієте ці відповіді, інакше ви все ще розгублені.

Якщо коротко, вам потрібно знати кілька моментів:

  1. import a дія насправді запускає все, що можна виконати в "а"

  2. Через пункт 1 ви, можливо, не хочете, щоб усе було запущено в "а" при імпорті

  3. Щоб вирішити проблему в пункті 2, python дозволяє поставити перевірку стану

  4. __name__є неявною змінною у всіх .pyмодулях; коли a.pyімпортується, значення __name__з a.pyмодуля встановлюється в імені файлу " a«; коли a.pyвиконується безпосередньо з допомогою « python a.py», що означає , a.pyяк точку входу, то значення __name__з a.pyмодуля встановлюється в рядок__main__

  5. Виходячи з механізму, як python встановлює змінну __name__для кожного модуля, чи знаєте ви, як досягти точки 3? Відповідь досить проста, правда? Поміщений якщо умова: if __name__ == "__main__": ...; Ви навіть можете поставити, якщо це __name__ == "a"залежить від вашої функціональної потреби

Важливе, що пітон особливий, - це точка 4! Решта - лише основна логіка.


1
Так, важливо розуміти пункт 1. З цього стає зрозумілою необхідність цього механізму.
Еврика

16

Поміркуйте:

print __name__

Вихід для вищезазначеного є __main__.

if __name__ == "__main__":
  print "direct method"

Вищенаведене твердження вірно і друкує "прямий метод" . Припустимо, якщо вони імпортували цей клас в інший клас, він не друкує "прямий метод", оскільки під час імпорту він встановить __name__ equal to "first model name".


14

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

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


14

Причина для

if __name__ == "__main__":
    main()

насамперед, щоб уникнути проблем із блокуванням імпорту, які виникатимуть із безпосередньо імпортованим кодом . Ви хочете main()запустити, якщо ваш файл був безпосередньо виклик (саме __name__ == "__main__"так), але якщо ваш код був імпортований, імпортер повинен ввести ваш код з основного основного модуля, щоб уникнути проблем із блокуванням імпорту.

Побічним ефектом є те, що ви автоматично входите в методологію, яка підтримує кілька точок входу. Ви можете запустити свою програму, використовуючи main()як точку входу, але цього не потрібно . У той час як setup.pyпередбачається main(), інші інструменти використовують альтернативні точки входу. Наприклад, щоб запустити файл як gunicornпроцес, ви визначите app()функцію замість main(). Як і у випадку setup.py, gunicornімпортуйте свій код, щоб ви не хотіли, щоб він робив щось під час імпорту (через проблему блокування імпорту).


3
Добре дізнатися про замок імпорту . Чи можете ви пояснити, чи потрібно ввійти до методології, яка [...] розібралася трохи більше?
Вовк

1
@ Вовк: Звичайно. Я додав кілька речень про методологію декількох вхідних точок.
personal_cloud

11

Ця відповідь призначена для Java-програмістів, які навчаються Python. Кожен файл Java зазвичай містить один відкритий клас. Ви можете використовувати цей клас двома способами:

  1. Виклик класу з інших файлів. Вам просто потрібно імпортувати його в програму виклику.

  2. Виконайте клас самостійно, для тестування.

В останньому випадку клас повинен містити загальнодоступний метод static void main (). У Python цій цілі служить глобально визначена мітка '__main__'.


11

Код під if __name__ == '__main__': буде виконуватися лише у тому випадку, якщо модуль викликається як сценарій .

Як приклад розглянемо наступний модуль my_test_module.py:

# my_test_module.py

print('This is going to be printed out, no matter what')

if __name__ == '__main__':
    print('This is going to be printed out, only if user invokes the module as a script')

Перша можливість: імпорт my_test_module.pyв інший модуль

# main.py

import my_test_module

if __name__ == '__main__':
    print('Hello from main.py')

Тепер якщо ви посилаєтесь main.py:

python main.py 

>> 'This is going to be printed out, no matter what'
>> 'Hello from main.py'

Зауважте, що виконується лише print()оператор верхнього рівня в my_test_module.


2-а можливість: Викликати my_test_module.pyяк сценарій

Тепер, якщо ви запускаєте my_test_module.pyяк скрипт Python, обидва print()твердження будуть виконані:

python my_test_module.py

>>> 'This is going to be printed out, no matter what'
>>> 'This is going to be printed out, only if user invokes the module as a script'

10

Кожен модуль у python має атрибут, який називається __name__. Значення __name__ атрибута - це __main__ коли модуль запускається безпосередньо, як python my_module.py. В іншому випадку (наприклад, коли ви говорите import my_module) значення __name__ - це ім'я модуля.

Невеликий приклад для пояснення коротко.

#Script test.py

apple = 42

def hello_world():
    print("I am inside hello_world")

if __name__ == "__main__":
    print("Value of __name__ is: ", __name__)
    print("Going to call hello_world")
    hello_world()

Ми можемо виконати це безпосередньо як

python test.py  

Вихідні дані

Value of __name__ is: __main__
Going to call hello_world
I am inside hello_world

Тепер припустимо, що ми зателефонуємо вище за іншими сценаріями

#script external_calling.py

import test
print(test.apple)
test.hello_world()

print(test.__name__)

Коли ви виконаєте це

python external_calling.py

Вихідні дані

42
I am inside hello_world
test

Отже, вище пояснюється, що коли ви викликаєте тест з іншого скрипту, якщо цикл __name__в test.pyне виконається.


6

Якщо цей .py-файл імпортується іншими .py-файлами, код під "оператором if" не буде виконаний.

Якщо цей .py працює python this_py.pyпід оболонкою або двічі клацніть у Windows. код у розділі "оператор if" буде виконаний.

Зазвичай пишеться для тестування.


6

Якщо інтерпретатор python працює під конкретним модулем, то __name__глобальна змінна матиме значення"__main__"

  def a():
      print("a")
  def b():
      print("b")

  if __name__ == "__main__": 

          print ("you can see me" )
          a()
  else: 

          print ("You can't see me")
          b()

Коли ви запускаєте цей відбиток сценарію, ви можете бачити мене

а

Якщо ви імпортуєте цей файл, скажімо, A у файл B та виконаєте файл B, тоді if __name__ == "__main__"у файлі A стає неправдивим, тому він друкує, Ви не можете мене бачити

б


5

Усі відповіді в значній мірі пояснили функціональність. Але я наведу один приклад його використання, який може допомогти далі очистити концепцію.

Припустимо, що у вас є два файли Python, a.py та b.py. Тепер, a.py імпортує b.py. Запускаємо файл a.py, де спочатку виконується код "імпортувати b.py". Перед запуском решти коду a.py код у файлі b.py повинен запуститися повністю.

У коді b.py є якийсь код, який є ексклюзивним для цього файлу b.py, і ми не хочемо, щоб будь-який інший файл (крім файлу b.py), який імпортував файл b.py, запускав його.

Так це перевіряє цей рядок коду. Якщо в основному файлі (тобто b.py) працює код, який у цьому випадку не є (a.py - головний файл, що працює), тоді виконується лише код.


4

Створіть файл, a.py :

print(__name__) # It will print out __main__

__name__завжди дорівнює тому, __main__коли цей файл запускається безпосередньо, показуючи, що це основний файл.

Створіть інший файл, b.py , у тому самому каталозі:

import a  # Prints a

Виконати його. Він надрукує а , тобто ім'я імпортованого файлу .

Отже, щоб показати дві різні поведінки одного файлу , це загальноприйнята хитрість:

# Code to be run when imported into another python file

if __name__ == '__main__':
    # Code to be run only when run directly

4

якщо ім'я == ' головний ':

Ми бачимо, якщо __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__

4

Просто це вхідна точка для запуску файлу, як і mainфункція на мові програмування C.


8
Ця відповідь робить припущення, що ОП (або будь-який користувач із подібним запитанням) одночасно знайомий з C і знає, що таке точка входу.
arredond

1
Ця відповідь також передбачає, що жоден код (крім визначень без побічних ефектів) перед if __name__ == "__main__"блоком не має місце. Технічно вершина виконаного сценарію - це точка входу програми.
Чарлі Хардінг
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.