What does if __name__ == "__main__": do? 해결법
단답
그것은 사용자가 의도하지 않았을 때 실수로 스크립트를 호출하는 것을 방지하는 상용 코드이다. 다음은 스크립트에서 가드가 누락될 때 발생하는 몇 가지 일반적인 문제입니다
- 다른 스크립트에서 가드 없는 스크립트를 가져오면(예:
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
- 가져오기 전에 문자열
(따옴표 없이)를 출력합니다.
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")
- function_a"
앞에 문자열
를 출력합니다.
- 이것은
def
블록을 실행하여 함수 객체를 만든 다음, 그 함수 객체를function_a
라는 변수에 할당한다. - function_b" 앞에 문자열
를 출력합니다.
- 두 번째
def
블록을 실행하여 다른 함수 객체를 만든 다음, 이를function_b
라는 변수에 할당한다. - 문자열
"before__name__guard"
를 출력합니다.
<강함>모듈이 메인 프로그램일 때만 해당 </강함>
- 만약 당신의 모듈이 메인 프로그램이라면, 그것은 실제로
_name__/code>가
"__main__"/code"로 설정되어 있다는 것을 볼 것이고, 그것은 문자열을 인쇄하면서 두 함수를 호출한다함수 A"
및 "기능 B 10.0"
.
<강함>다른 사람이 모듈을 가져올 때만 해당 </강함>
- ( 대신에 ) 모듈이 메인 프로그램이 아니라 다른 프로그램에 의해 가져온 경우,
_name__
는"_main_"
가 아니라"foo"가 되며,
if
문의 본문을 건너뜁니다.
Always
- 두 경우 모두 문자열
"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")
</너>