__main__
— 최상위 코드 환경¶
파이썬에서 특수 이름 __main__
은 두 가지 중요한 구조에 사용됩니다:
프로그램의 최상위 환경 이름으로,
__name__ == '__main__'
식을 사용하여 확인 할 수 있습니다; 그리고파이썬 패키지의
__main__.py
파일입니다.
이 두 메커니즘은 파이썬 모듈과 관련이 있으며, 사용자가 그것과 상호작용을 하는 방식과 그들끼리 상호작용을 하는 방식에 관한 것입니다. 자세한 내용은 아래에서 설명합니다. 파이썬의 모듈이 처음이라면 자습서의 모듈 를 참고하십시오.
__name__ == '__main__'
¶
파이썬 모듈이나 패키지가 임포트 되면, __name__
은 해당 모듈의 이름으로 설정됩니다. 보통, 이름은 .py
확장자를 제외한 파이썬 파일 자체의 이름입니다:
>>> import configparser
>>> configparser.__name__
'configparser'
파일이 패키지의 일부라면, __name__
은 상위 패키지 경로도 포함합니다:
>>> from concurrent.futures import process
>>> process.__name__
'concurrent.futures.process'
그러나 모듈이 최상위 코드 환경에서 실행될 경우, __name__
은 문자열 __main__
으로 설정됩니다.
“최상위 코드 환경” 이란 무엇인가요?¶
__main__
은 최상위 코드가 실행되는 환경의 이름입니다. “최상위 코드” 란 사용자가 지정한 첫 번째 파이썬 모듈로, 실행을 시작하는 모듈입니다. “최상위” 라고 부르는 이유는 프로그램이 필요로 하는 다른 모든 모듈을 임포트하기 때문입니다. 때때로 “최상위 코드” 는 응용 프로그램의 진입 지점 이라고도 합니다.
최상위 코드 환경은 다음과 같습니다:
대화형 프롬프트의 스코프:
>>> __name__ '__main__'
파이썬 인터프리터에 파일 인자로 전달된 파이썬 모듈:
$ python helloworld.py Hello, world!
파이썬 인터프리터
-m
인자로 전달된 파이썬 모듈이나 패키지:$ python -m tarfile usage: tarfile.py [-h] [-v] (...)
표준 입력으로부터 파이썬 인터프리터가 읽은 코드:
$ echo "import this" | python The Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is better than implicit. ...
파이썬 인터프리터에
-c
인자로 전달된 파이썬 코드:$ python -c "import this" The Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is better than implicit. ...
이러한 모든 경우에서, 최상위 모듈의 __name__
은 '__main__'
으로 설정됩니다.
결과적으로, 모듈은 자신의 __name__
을 검사하여 최상위 환경에서 실행 중인지를 확인할 수 있습니다. 이 때문에 모듈이 임포트 문에서 초기화되지 않을 때 조건부로 코드를 실행하는 공통 관용구를 사용할 수 있습니다:
if __name__ == '__main__':
# 모듈이 임포트 문에서 초기화되지 않을 때 실행합니다.
...
더 보기
__name__
이 다양한 상황에서 어떻게 설정되는 것에 대한 자세한 내용은 자습서의 모듈 을 참고하십시오.
관용적 사용법¶
일부 모듈에는 명령줄 인자를 분석하거나 표준 입력에서 데이터를 가져오는 등, 스크립트용으로만 의도된 코드가 포함되어 있습니다. 이러한 모듈을 다른 모듈에서 임포트하면, 예를 들어 유닛 테스트를 위해 임포트를 할 때도, 스크립트 코드가 의도치 않게 실행될 수 있습니다.
이럴 때 if __name__ == '__main__'
코드 블록을 사용하면 유용합니다. 이 블록 안의 코드는 모듈이 최상위 환경에서 실행되지 않는 한 실행되지 않습니다.
if __name__ == '__main__'
아래의 블록에서는 가능한 적은 구문을 두는 것이 코드의 명확성과 정확성을 높일 수 있습니다. 대부분은 main
이라는 함수를 정의해 프로그램의 주요 동작을 캡슐화합니다:
# echo.py
import shlex
import sys
def echo(phrase: str) -> None:
"""print 를 둘러싼 더미 래퍼."""
# 시연의 목적으로, 이 함수 안에 쓸모있고 재사용할 수 있는
# 로직이 있다고 상상할 수 있습니다
print(phrase)
def main() -> int:
"""입력 인자를 표준 출력으로 에코합니다"""
phrase = shlex.join(sys.argv)
echo(phrase)
return 0
if __name__ == '__main__':
sys.exit(main()) # 다음 절에서 sys.exit 의 사용에 대해 설명합니다
모듈이 코드를 main
함수 안에 캡슐화하지 않고 if __name__ == '__main__'
블록 안에 직접 작성한다면, phrase
는 모듈 전체에서 전역 변수가 됩니다. 이 경우 모듈 내의 다른 함수들이 지역 이름 대신 전역 변수를 의도치 않게 사용할 수 있어 오류가 발생하기 쉽습니다. main
함수는 이러한 문제를 해결합니다.
main
함수를 사용하는 또 다른 장점은 echo
함수 자체와 분리되어 다른 곳에서도 임포트 할 수 있다는 점입니다. echo.py
가 임포트 되면 echo
와 main
함수가 정의되지만, __name__ != '__main__'
이므로 두 함수 중 어느 것도 호출되지 않습니다.
패키징 고려 사항¶
main
함수는 콘솔 스크립트의 진입 지점으로 지정하여 명령줄 도구를 만들 때 자주 사용됩니다. 이 경우 pip 는 함수 호출을 템플릿 스크립트에 삽입하며, main
의 반환 값은 sys.exit()
로 전달됩니다. 예를 들면:
sys.exit(main())
main
호출이 sys.exit()
로 감싸져 있으므로, 함수는 sys.exit()
의 입력으로 사용될 수 있는 값을 반환해야 합니다. 일반적으로 이는 정수이거나, 함수의 반환문이 없는 경우 암묵적으로 반환되는 None
입니다.
이 규칙을 따름으로써, 모듈은 나중에 pip로 설치 가능한 패키지의 콘솔 스크립트 진입 지점으로 배포되더라도, 직접 실행할 때 (예를 들어 python echo.py
)와 동일한 동작을 하게 됩니다.
특히 main
에서 문자열을 반환할 때 주의해야 합니다. sys.exit()
함수는 문자열 인자를 실패 메시지로 해석하므로, 프로그램의 종료 코드는 실패를 의미하는 1
이 되고, 문자열은 sys.stderr
에 기록됩니다. 앞서 언급한 echo.py
의 예제는 sys.exit(main())
규칙 사용을 잘 보여줍니다.
더 보기
Python Packaging User Guide 는 현대적인 도구를 사용하여 파이썬 패키지를 배포하고 설치하는 방법에 대한 자습서와 참고 자료를 제공합니다.
파이썬 패키지의 __main__.py
¶
파이썬 패키지에 익숙하지 않다면, 자습서의 패키지 를 참고하십시오. 대부분의 경우 __main.py__
파일은 패키지에 명령줄 인터페이스를 제공하는 데 사용됩니다. 다음은 가상의 패키지 “bandclass” 예시입니다:
bandclass
├── __init__.py
├── __main__.py
└── student.py
-m
플래그를 사용해 명령줄에서 패키지 자체를 직접 호출하면, __main__.py
가 실행됩니다. 예를 들어:
$ python -m bandclass
이 명령은 __main__.py
를 실행시킵니다. 이 메커니즘을 어떻게 활용할지는 작성 중인 패키지의 성격에 따라 달라지지만, 이 가상의 예시에서는 교사가 학생을 검색할 수 있도록 하는 것이 합리적일 것입니다:
# bandclass/__main__.py
import sys
from .student import search_students
student_name = sys.argv[1] if len(sys.argv) >= 2 else ''
print(f'Found student: {search_students(student_name)}')
from .student import search_students
는 상대 임포트의 예시입니다. 이 임포트 방식은 패키지 내부의 모듈을 참조할 때 사용할 수 있습니다. 자세한 내용은 자습서의 모듈 부분의 패키지 내부 간의 참조 를 참고하십시오.
관용적 사용법¶
일반적으로 __main__.py
의 내용은 if __name__ == '__main__'
블록으로 감싸지 않습니다. 대신, 파일을 간결하게 유지하고 실행할 함수들을 다른 모듈에서 임포트합니다. 이렇게 하면 다른 모듈은 손쉽게 단위 테스트할 수 있고, 재사용하기에도 적합합니다.
만약 사용할 때에도, 패키지 내의 __main__.py
파일에서는 if __name__ == '__main__'
블록이 예상대로 동작합니다. 임포트될 때 __name__
속성에 패키지의 경로가 포함되기 때문입니다:
>>> import asyncio.__main__
>>> asyncio.__main__.__name__
'asyncio.__main__'
그러나 .zip
파일의 루트 디렉터리에 있는 __main__.py
파일에서는 이 방식이 작동하지 않습니다. 따라서 일관성을 위해 __name__
검사를 포함하지 않은 최소한의 __main__.py
를 사용하는 것이 권장됩니다.
import __main__
¶
파이썬 프로그램이 어떤 모듈에서 시작되었는지와 관계없이, 같은 프로그램 내의 다른 모듈들은 __main__
모듈을 임포트하여 최상위 환경의 스코프(namespace)를 불러올 수 있습니다. 이는 __main__.py
파일을 임포트하는 것이 아니라, 특수한 이름 '__main__'
을 부여받은 모듈을 임포트하는 것입니다.
다음은 __main__
네임스페이스를 사용하는 모듈의 예시입니다:
# namely.py
import __main__
def did_user_define_their_name():
return 'my_name' in dir(__main__)
def print_user_name():
if not did_user_define_their_name():
raise ValueError('Define the variable `my_name`!')
print(__main__.my_name)
이 모듈의 사용 예시는 다음과 같습니다:
# start.py
import sys
from namely import print_user_name
# my_name = "Dinsdale"
def main():
try:
print_user_name()
except ValueError as ve:
return str(ve)
if __name__ == "__main__":
sys.exit(main())
이제 프로그램을 실행하면 결과는 다음과 같을 것입니다:
$ python start.py
Define the variable `my_name`!
프로그램의 종료 코드는 오류를 나타내는 1이 됩니다. my_name = "Dinsdale"
줄의 주석을 해제하면 프로그램이 정상 동작하며, 이제 상태 코드 0으로 종료되어 성공을 의미하게 됩니다:
$ python start.py
Dinsdale
__main__
을 임포트하더라도, start
모듈의 if __name__ == '__main__'
블록에 있는 스크립트 전용 코드가 의도치 않게 실행되는 문제는 발생하지 않습니다. 왜 그럴까요?
파이썬은 인터프리터 시작 시 sys.modules
에 빈 __main__
모듈을 삽입하고, 최상위 코드를 실행하면서 이를 채웁니다. 이 예제에서 그 최상위 모듈은 start
이며, 한 줄씩 실행되면서 namely
를 임포트합니다. 그런데 namely
는 다시 __main__
(즉, 실제로는 start
) 을 임포트합니다. 이는 임포트 순환입니다! 다행히도, 부분적으로 채워진 __main__
모듈이 이미 sys.modules
에 존재하므로, 파이썬은 그것을 namely
에 전달합니다. 이 동작 방식에 대한 자세한 내용은 import 시스템 레퍼런스의 __main__ 에 대한 특수 고려 사항 을 참고하십시오.
파이썬 REPL은 또 다른 형태의 ‘최상위 환경’ 예시이므로, REPL에서 정의된 모든 것은 __main__
스코프의 일부가 됩니다:
>>> import namely
>>> namely.did_user_define_their_name()
False
>>> namely.print_user_name()
Traceback (most recent call last):
...
ValueError: Define the variable `my_name`!
>>> my_name = 'Jabberwocky'
>>> namely.did_user_define_their_name()
True
>>> namely.print_user_name()
Jabberwocky
__main__
스코프는 pdb
와 rlcompleter
의 구현에서도 사용됩니다.