__main__ — 최상위 코드 환경


파이썬에서 특수 이름 __main__ 은 두 가지 중요한 구조에 사용됩니다:

  1. 프로그램의 최상위 환경 이름으로, __name__ == '__main__' 식을 사용하여 확인 할 수 있습니다; 그리고

  2. 파이썬 패키지의 __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 가 임포트 되면 echomain 함수가 정의되지만, __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 를 사용하는 것이 권장됩니다.

더 보기

표준 라이브러리에서 최소한의 __main__.py 를 가진 패키지 예시로는 venv 를 들 수 있습니다. 이 모듈에는 if __name__ == '__main__' 블록이 포함되어 있지 않으며, python -m venv [directory] 명령으로 호출할 수 있습니다.

-m 플래그에 대한 자세한 내용은 runpy 모듈을 참고하십시오.

.zip 파일로 패키징된 애플리케이션을 실행하는 방법은 zipapp 모듈을 참고하십시오. 이 경우 파이썬은 아카이브의 루트 디렉터리에서 __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__ 스코프는 pdbrlcompleter 의 구현에서도 사용됩니다.