파이썬

[Python] if __name__ == "__main__": 하면 어떻게 되나요?

zooheon 2022. 7. 31. 13:41
반응형

이것은 무엇을 하며, 왜 이 if명령문을 포함해야 합니까?

if __name__ == "__main__":
    print("Hello, World!")

 

짧은 대답

의도하지 않은 스크립트를 실수로 호출하지 않도록 사용자를 보호하는 상용구 코드입니다. 다음은 스크립트에서 가드를 생략할 때 발생하는 몇 가지 일반적인 문제입니다.

  • 다른 스크립트(예: )에서 가드리스 ​​스크립트를 가져오는 경우 후자의 스크립트는 가져오기 시 두 번째 스크립트의 명령줄 인수를 사용하여 전자 import my_script_without_a_name_eq_main_guard를 실행하도록 트리거합니다 . 이것은 거의 항상 실수입니다.

  • 가드리스 스크립트에 사용자 정의 클래스가 있고 이를 피클 파일에 저장한 경우 다른 스크립트에서 이를 언피클링하면 가드리스 ​​스크립트 가져오기가 트리거되며 이전 글머리 기호에서 설명한 것과 동일한 문제가 발생합니다.

긴 답변

이것이 왜 그리고 어떻게 중요한지 더 잘 이해하려면 Python이 스크립트를 초기화하는 방법과 이것이 모듈 가져오기 메커니즘과 상호 작용하는 방법을 이해하기 위해 한 걸음 물러서야 합니다.

Python 인터프리터는 소스 파일을 읽을 때마다 두 가지 작업을 수행합니다.

  • 와 같은 몇 가지 특수 변수를 설정한 __name__다음

  • 파일에서 찾은 모든 코드를 실행합니다.

__name__이것이 어떻게 작동하고 Python 스크립트에서 항상 볼 수 있는 검사에 대한 귀하의 질문과 어떻게 관련되는지 봅시다 .

코드 샘플

약간 다른 코드 샘플을 사용하여 가져오기 및 스크립트가 작동하는 방식을 살펴보겠습니다. 다음이 라는 파일에 있다고 가정합니다 foo.py.

# Suppose this is foo.py.

print("before import")
import math

print("before function_a")
def function_a():
    print("Function A")

print("before function_b")
def function_b():
    print("Function B {}".format(math.sqrt(100)))

print("before __name__ guard")
if __name__ == '__main__':
    function_a()
    function_b()
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

인터프리터는 파일을 검색하고(몇 가지 다른 변형 검색과 함께) 해당 모듈을 실행하기 전에 import 문에서 변수에 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 function_a".

  2. 블록을 실행하여 def함수 개체를 만든 다음 해당 함수 개체를 이라는 변수에 할당합니다 function_a.

  3. 그것은 문자열을 인쇄합니다 "before function_b".

  4. 두 번째 def블록을 실행하여 다른 함수 개체를 만든 다음 이라는 변수에 할당합니다 function_b.

  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 function_a
before function_b
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 function_a
before function_b
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 function_a():
    print("a1")
    from foo2 import function_b
    print("a2")
    function_b()
    print("a3")

def function_b():
    print("b")

print("t1")
if __name__ == "__main__":
    print("m1")
    function_a()
    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 function_a():
    print("a1")
    from foo3 import function_b
    print("a2")
    function_b()
    print("a3")

def function_b():
    print("b")

print("t1")
print("m1")
function_a()
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")

 

스크립트를 Python 인터프리터에 명령으로 전달하여 스크립트를 실행할 때,

python myscript.py

들여쓰기 수준 0에 있는 모든 코드가 실행됩니다. 정의된 함수와 클래스는 잘 정의되어 있지만 코드가 실행되지는 않습니다. 다른 언어와 달리 main()자동으로 실행되는 함수가 없습니다. main()함수는 암시적으로 최상위 수준의 모든 코드입니다.

이 경우 최상위 코드는 if블록입니다. __name__현재 모듈의 이름으로 평가되는 내장 변수입니다. 그러나 모듈이 직접 실행되는 경우(위에서와 myscript.py같이) __name__대신 가 string 으로 설정됩니다 "__main__". 따라서 스크립트가 직접 실행되고 있는지 테스트를 통해 다른 것으로 가져오는지 테스트할 수 있습니다.

if __name__ == "__main__":
    ...

스크립트를 다른 모듈로 가져오는 경우 다양한 함수 및 클래스 정의를 가져오고 최상위 코드가 실행되지만 if위 절의 then-body에 있는 코드는 조건이 다음과 같이 실행되지 않습니다. 충족시키지 못함. 기본 예제로 다음 두 스크립트를 고려하십시오.

# 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__".

 

다음 두 파일을 만듭니다.

# a.py

import b
# b.py

print("__name__ equals " + __name__)

if __name__ == '__main__':
    print("if-statement was executed")

이제 각 파일을 개별적으로 실행하십시오.


실행 중 python a.py:

$ python a.py
__name__ equals b

가 실행 되면 a.py모듈을 가져옵니다 b. 이렇게 하면 내부의 모든 코드 b가 실행됩니다. Python은 globals()['__name__']모듈 b에서 모듈의 이름인 b.


실행 중 python b.py:

$ python b.py
__name__ equals __main__
if-statement was executed

파일만 b.py실행될 때 Python은 globals()['__name__']이 파일을 "__main__". 따라서 if명령문은 True이 시간으로 평가됩니다.

 

반응형