파이썬의 모듈 객체는 여러 가지 속성(attribute)으로 구성되어 있으며, 속성 이름 앞뒤에는 이중 언더스코어(dunder, __)가 붙는 것이 특징입니다. 그중에서도 가장 중요한 속성은 바로 __name__입니다. 이 속성의 값을 이해하면 파이썬 스크립트가 '직접 실행'되는 상황인지, 아니면 '다른 곳에서 임포트'되는 상황인지를 정확히 구분할 수 있습니다.
__name__ 속성의 기본 동작
파이썬이 최상위(top-level) 실행 코드로 동작할 때, 즉 표준 입력, 스크립트 파일, 또는 대화형 인터프리터 프롬프트에서 코드를 직접 읽어 실행하는 경우에는 __name__ 속성이 '__main__'으로 설정됩니다.
>>> __name__ '__main__'
스크립트 파일 내부에서도 마찬가지입니다. 아래와 같은 간단한 스크립트를 실행해 보면 __name__ 값이 '__main__'으로 출력됩니다.
'''module docstring'''
print('name of module:', __name__)실행 결과
name of module: __main__
임포트된 모듈의 __name__ 값
반면, 다른 곳에서 임포트된 모듈의 __name__ 속성은 해당 파이썬 파일의 이름으로 설정됩니다. 예를 들어 hello.py라는 모듈을 임포트하면 다음과 같습니다.
>>> import hello >>> hello.__name__ 'hello'
즉, 최상위 모듈의 __name__ 값은 '__main__'이지만, 임포트된 모듈의 __name__ 값은 파일명이 됩니다. 아래와 같은 스크립트(moduletest.py)로 이 차이를 확인할 수 있습니다.
import hello
print('name of top level module:', __name__)
print('name of imported module:', hello.__name__)실행 결과
name of top level module: __main__ name of imported module: hello
문제 상황: 임포트 시 실행 코드가 자동으로 동작한다
함수를 포함한 파이썬 스크립트에는 함수 정의 외에 실행 가능한 코드가 함께 들어 있는 경우가 많습니다. 그런데 이런 모듈을 임포트하면 함수 정의뿐 아니라 그 실행 코드까지 자동으로 수행되어 버립니다.
예를 들어 두 개의 함수를 가진 messages.py 스크립트가 있다고 가정해 봅시다. 실행 부분에서는 사용자 입력을 받아 thanks() 함수의 인자로 전달합니다.
def welcome(name):
print('Hi {}. Welcome to TutorialsPoint'.format(name))
return
def thanks(name):
print('Thank you {}. See you again'.format(name))
name = input('enter name:')
thanks(name)messages.py를 직접 실행하면 당연히 감사 메시지가 출력됩니다.
enter name:Ajit Thank you Ajit. See you again
그런데 이 모듈의 함수만 가져다 쓰기 위해 아래와 같은 moduletest.py를 작성해 실행하면 어떻게 될까요?
import messages
print('name of top level module:', __name__)
print('name of imported module:', messages.__name__)c:\python37>python moduletest.py
실행 결과
enter name:Kishan Thank you Kishan. See you again
moduletest.py를 실행했을 뿐인데, 임포트 과정에서 messages 모듈 안의 input 문과 thanks() 함수 호출이 함께 실행되어 버렸습니다. 우리가 원하는 것은 messages 모듈의 함수를 가져오는 것이지, 모듈 내부의 실행 코드까지 수행하는 것이 아닙니다.
해결책: if __name__ == '__main__' 패턴
바로 이 지점에서 '최상위 스크립트의 __name__ 값은 __main__이다'라는 사실이 유용하게 쓰입니다. messages.py를 다음과 같이 수정하여, input 문과 함수 호출이 __name__이 '__main__'일 때만 실행되도록 만들면 됩니다.
'''docstring of messages module'''
def welcome(name):
print('Hi {}. Welcome to TutorialsPoint'.format(name))
return
def thanks(name):
print('Thank you {}. See you again'.format(name))
if __name__ == '__main__':
name = input('enter name:')
thanks(name)이제 moduletest.py는 전혀 수정할 필요가 없습니다. messages 모듈을 임포트하면 welcome() 같은 함수는 그대로 사용할 수 있으면서, 모듈 내부의 실행 부분은 더 이상 자동으로 동작하지 않습니다.
enter name: milind Hi milind. Welcome to TutorialsPoint
정리
이처럼 if __name__ == '__main__': 패턴은 하나의 파일을 '직접 실행되는 스크립트'와 '임포트되는 모듈' 두 가지 용도로 모두 활용하고 싶을 때 반드시 사용해야 하는 관용적(idiomatic) 기법입니다. 참고로 이 조건문을 추가한다고 해서 messages.py를 독립적으로 실행하는 것이 막히는 것은 아니므로, 기존 스크립트의 동작에는 아무런 영향이 없습니다.