What does if __name__ == "__main__": do? 해결법

728x90
반응형

단답

그것은 사용자가 의도하지 않았을 때 실수로 스크립트를 호출하는 것을 방지하는 상용 코드이다. 다음은 스크립트에서 가드가 누락될 때 발생하는 몇 가지 일반적인 문제입니다

  • 다른 스크립트에서 가드 없는 스크립트를 가져오면(예: Import my_script_without_a_name_eq_main_guard) 후자의 스크립트는 전자를 가져올 때 실행하고 두 번째 스크립트의 명령줄 인수를 사용하여 실행합니다. 이것은 거의 항상 실수이다.
  • 가드리스 스크립트에 사용자 지정 클래스가 있고 이 클래스를 피클 파일에 저장한 경우 다른 스크립트에서 선택을 해제하면 이전 글머리표에서 설명한 것과 동일한 문제가 발생하여 가드리스 스크립트를 가져올 수 있습니다.

긴 대답

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

파이썬 인터프리터는 소스 파일을 읽을 때마다 두 가지 작업을 수행한다:

  • __name_와 같은 몇 가지 특수 변수를 설정한 다음
  • 파일에 있는 모든 코드를 실행합니다.

이것이 어떻게 작동하는지, 그리고 파이썬 스크립트에서 항상 볼 수 있는 _name_/code에 대한 질문과 어떻게 관련이 있는지 알아보자.

코드 샘플

조금 다른 코드 샘플을 사용하여 가져오기 및 스크립트의 작동 방식을 살펴보겠습니다. 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") 

특수변수

파이썬 인터프리터는 소스 파일을 읽을 때 먼저 몇 가지 특수 변수를 정의합니다. 이 경우, 우리는 _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 파일을 검색하고, 모듈을 실행하기 전에, _name__ 변수에 "foo"라는 이름을 할당할 것이다

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

모듈 코드 실행

특수 변수가 설정된 후 인터프리터는 모듈의 모든 코드를 한 번에 하나의 문으로 실행합니다. 코드 샘플이 있는 쪽의 다른 창을 열어서 이 설명을 따를 수 있습니다.

Always

  1. 가져오기 전에 문자열 (따옴표 없이)를 출력합니다.
  2. math 모듈을 로드하여 math라는 변수에 할당합니다. 이것은 가져오기 함수를 다음과 같이 대체하는 것과 같다(_import__는 문자열을 가져와서 실제 가져오기를 트리거하는 파이썬의 낮은 수준 함수이다):

# Find and load a module given its string name, "math", # then assign it to a local variable called math. math = __import__("math") 

  1. function_a"

앞에 문자열 를 출력합니다.

 

  • 이것은 def블록을 실행하여 함수 객체를 만든 다음, 그 함수 객체를 function_a라는 변수에 할당한다.
  • function_b" 앞에 문자열 를 출력합니다.
  • 두 번째 def 블록을 실행하여 다른 함수 객체를 만든 다음, 이를 function_b라는 변수에 할당한다.
  • 문자열 "before__name__guard" 를 출력합니다.

 

<강함>모듈이 메인 프로그램일 때만 해당 </강함>

      만약 당신의 모듈이 메인 프로그램이라면, 그것은 실제로

_name__/code>가 "__main__"/code"로 설정되어 있다는 것을 볼 것이고, 그것은 문자열을 인쇄하면서 두 함수를 호출한다함수 A""기능 B 10.0" .

<강함>다른 사람이 모듈을 가져올 때만 해당 </강함>

  1. ( 대신에 ) 모듈이 메인 프로그램이 아니라 다른 프로그램에 의해 가져온 경우, _name__"_main_"가 아니라 "foo"가 되며, if 문의 본문을 건너뜁니다.

Always

  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에 다음이 있다고 가정합니다. 명령줄에서 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__/code>를 제거하면 어떻게 되는지 알아보세요. 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") 

</너>

728x90
반응형