Python

if __name__ == '__main__': 이 뭔가요?

둔진 2023. 1. 15. 13:04

파이썬 코드들을 보다보면 아래와 같은 코드를 종종 볼 수 있습니다.

if __name__ == '__main__':
    # something here

이 코드가 하는 일은 무엇일까요? 오늘은 이 코드의 작동 원리와 언제 사용하는지 알아보겠습니다.

__name__ 은 무엇일까요?

먼저 첫번째 퍼즐 조각인 __name__이 무엇인지부터 알아보겠습니다.

Python에는 미리 정의된 특수한 함수나 변수들이 있습니다. 함수는 __do()__ 같은 형태이고, 변수는 __val__ 같은 형태입니다. 이런 특수한 함수와 변수는 보통 Python 내부적으로 사용하기 위한 것들이라서 코딩 때 직접 사용할 일은 그다지 많지 않습니다. 그런데 __name__은 아주 유용한 특성이 있어서 일반 코딩 때도 곧잘 사용되곤 합니다. 좋은 것들은 잘 써야지요 :)

Python Interpreter가 코드를 처음 읽을 때 몇가지 동작을 하는데 그 중 하나가 바로 __name__ 변수를 정의하고 값을 채우는 것입니다. 그렇다면 Python Interpreter가 코드를 읽는 때는 언제일까요? 1) 다른 코드가 해당 파일을 import하거나 2) Python Interpreter가 해당 파일을 직접 실행 할 때입니다.

실제 동작을 알아보기 위해서 아래와 같은 코드를 my_module.py라고 저장합니다.

def useful_task():
    print("I am a very useful function!")

print('__name__:', __name__)

함수 하나를 선언하고, __name__의 값을 출력하는 코드입니다.

코드가 import 될 때 __name__

import 될 때 동작으르 보기 위해서 main.py 파일을 만들고 아래 내용을 작성해보겠습니다.

import my_module

my_module.useful_task()
>> python3 main.py
__name__: my_module
I am a very useful function!

첫번째 줄이 my_module.py가 import 되면서 실행된 결과입니다. __name__의 값이 my_module이라는 것을 알 수 있습니다. Python은 코드를 import 할 때 기본적으로 파일의 이름을 __name__에 저장합니다. 이 경우에는 my_module입니다.

Python Interpreter가 코드를 실행할 때

코드가 직접 실행될 때 동작을 보기위해 Shell에서 아래와 같이 명령을 내려보겠습니다.

>> python3 my_module.py
__name__: __main__

두번째 퍼즐 조각인 __main__이 나왔습니다. 코드를 import 할 때와는 다르게 Python Interpreter가 코드를 직접 실행할 때는 __name__의 값을 __main__으로 채웁니다. 실제 파일명과는 무관합니다.

그렇다면 이 코드가 하는 일은 무엇일까요?

아래와 같이 코드를 바꿔보겠습니다.

먼저 my_moduel.py입니다.

def useful_task():
    print("I am a very useful function!")

if __name__ == '__main__':
    useful_task()
    print("I can do another useful task as well!")

다음으로 main.py입니다.

import my_module

my_module.useful_task()
print("Stupid but fun task.")

main.py 실행

이제 main.py를 실행해보겠습니다.

>> python3 main.py
I am a very useful function!
Stupid but fun task.

main.pymy_module을 import 하고 있기 때문에 my_module.py 입장에서 __name__의 값은 my_module입니다. 즉, __name__ == '__main__'은 거짓이 되고 그 아래 코드들은 실행되지 않습니다.

my_module.py 실행

이번에는 my_module.py를 실행해보겠습니다.

>> python3 my_module.py
I am a very useful function!
I can do another useful task as well!

my_module.py를 직접 실행했기 때문에 my_module.py 입장에서 __name__의 값은 __main__이 됩니다. 이번에는 __name__ == '__main__'은 참이 되고 그 아래 코드들이 실행됩니다.

중간 정리

앞에서 본대로 if __name__ == '__main__':을 사용하면 파일이 import 될 때와 직접 실행될 때 실행될 코드를 제어할 수 있습니다. import 되든 직접 실행되든 관계없이 공통으로 실행되야하는 부분은 if __name__ == '__main__': 바깥에 두고, 직접 실행할때만 필요한 코드는 if __name__ == '__main__': 안에 넣으면 됩니다.

여기까지만이면 너무 심심하죠. 실전에서 쓰는 법을 알아보겠습니다

언제 이 표현을 쓸까요?

그렇다면 실전에서는 어떻게 사용할까요?

제가 사진에 강아지가 있다면 그 사진에서 강아지 부분을 표시히고 강아지의 종을 맞추는 프로그램을 만들고 있다고 가정해보겠습니다. 그리고 파일 이름은 identify_dog.py라고 해보겠습니다. 슈도 코드로 만들어 보자면 아래와 같은 모양일 것입니다.

def has_a_dog(image):
    pass

def mark_a_dog(image):
    pass

def predict_a_breed(image):
    pass

if has_a_dog(image):
    mark_a_dog(image)
    predict_a_breed(image)

이 자체로 좋은 프로그램이지만 생각해보니 has_a_dog(), mark_a_dog(), predict_a_breed() 같은 함수는 다른 곳에서도 유용하게 쓸일 것 같습니다. 그래서 identify_dog.py를 라이브러리(모듈)로 배포하기로 결심합니다.

하지만 문제가 있습니다.

import identify_dog

identify_dog.has_a_dog(image)

이라고 쓰고 싶은데 그렇게하면 if has_a_dog(image):와 그 아래 부분까지 실행됩니다. 라이브러리를 쓰는 입장에서는 불필요할 뿐만 아니라 오류를 발생시키는 것이죠.

한 가지 방법은 코드를 복사해서 두가지 배포본을 만드는 것입니다.

라이브러리용으로는 identify_dog_lib.py

def has_a_dog(image):
    pass

def mark_a_dog(image):
    pass

def predict_a_breed(image):
    pass

실행용으로는 identify_dog_script.py

def has_a_dog(image):
    pass

def mark_a_dog(image):
    pass

def predict_a_breed(image):
    pass

if has_a_dog(image):
    mark_a_dog(image)
    predict_a_breed(image)

똑같은 코드가 여러곳에 복사되어 있기 때문에 여러가지 문제가 있을 수 있습니다. 좋지 않은 방식입니다.

해결책은 if __name__ == '__main__':을 사용하는 것입니다. indentify_dog.py를 아래와 같이 만듭니다.

def has_a_dog(image):
    pass

def mark_a_dog(image):
    pass

def predict_a_breed(image):
    pass

if __name__ == '__main__':
    if has_a_dog(image):
        mark_a_dog(image)
        predict_a_breed(image)

이제 identify_dog.py를 직접 실행하면 if has_a_dog(image):와 그 아래 부분까지 실행되고, import를 한다면 그 앞까지만 실행됩니다.

부적절한 사용

이 방법을 사용하지 않아야할 때도 있을까요? 개인적으로 if __name__ == '__main__': 아래에는 진짜 실행을 위한 코드를 넣어야한다고 생각합니다. 작성하고 있는 모듈이 잘 작동하는지 테스트를 하기 위해서 if __name__ == '__main__': 아래에 테스트용 코드를 넣는 경우도 있는데요. 테스트를 위해서는 이 모듈을 import 하는 별도의 테스트 파일을 만들거나 test framework를 사용하는 것이 좋다고 생각합니다.

마무리

이번 포스트에서는 Python이 __name__을 어떻게 다루는지를 알아보았습니다. 그리고 이를 이용해 파일이 모듈로 import 될 때와 직접 실행될 때 동작을 다르게 할 수 있는 방법을 알아보았습니다.

실제 많은 Python 모듈들이 이 방식을 사용해서 모듈과 실행 스크립트의 역할을 모두 수행하고 있습니다.