brunch

You can make anything
by writing

C.S.Lewis

by 이권수 Mar 24. 2024

[Python] __main__ 의미

__main__을 사용하는 방법


파이썬은 애플리케이션을 개발할 때도 자주 사용되지만, 자동화 스크립트를 작성하거나 데이터 분석 코드를 수행할 때도 자주 사용된다. 그 중 간단한 자동화 스크립트 작성하는 경우, 개발자는 main.py 파일 하나에 모든 코드를 작성한다. 코드 자체가 길지 않기 때문에, 외부에 모듈을 따로 빼서 import 하는 번거로움을 굳이 가지지 않으려고 하는 목적이다. 이럴 때는 테스트하기도 간단하다. python main.py를 실행하면 바로 프로그램을 돌릴 수 있다.


그런데, 만약에 코드가 길어져서 파일을 분리한다고 가정해 보자. 그러면 하나의 프로그램으로 동작하기 위해서는 import(임포트)를 사용해 외부 모듈을 가져와서 사용해야 한다. 파일을 분리하게 되면, 역할에 맞게 함수나 객체 정의 등을 관리할 수 있으므로 간편하게 관리할 수 있다. 그래서 서비스를 만들거나, 코드 규모가 큰 경우에는 주로 파일을 분리한다. 


그러면 다음과 같이 사용할 수 있다.


먼저, calculator.py 파일을 추가하고, 기존에 main.py에 있던 calculate_sum, calculate_min 함수를 calculator.py로 옮긴다. 이후에 main.py에서는 calculator.py 모듈에서 calculate_sum, calculate_min 함수를 임포트 해서 사용한다. 

위와 결과는 동일하다


이때, calculate_sum과 calculate_min 함수가 제대로 동작하는지 테스트하고 싶다고 가정해 보자. 그러면 main.py 함수에 다음과 같이 테스트 코드를 추가할 수 있다. 참고로, assert 구문은 수식이 False인 경우, AssertionError를 내서, 프로그램의 버그를 잡아낼 수 있다.


위 방식의 문제는 main.py에서 모든 모듈 함수의 동작을 테스트해야 한다는 점이다. 예컨대, calculate_sum() 함수가 매우 복잡한 로직이라고 해보자. 그러면 개발자는 해당 함수를 수정할 때마다 main.py 파일을 실행하면서 테스트를 해야 한다. 만약 모듈이 여러 개라서 테스트가 오래 걸린다고 하면, 함수 하나를 테스트하기 위해 모든 테스트를 다 돌려야 하는 불편함을 감수해야 하는 것이다.


이를 방지하는 방법은 calculate_sum()을 정의한 calculator.py 내에서 테스트 코드를 돌리는 것이다. 그러면 각 모듈 내에서 테스트를 할 수 있기 때문에, 테스트 코드를 간편하게 돌릴 수 있다. 이제는 main.py를 돌리지 않고, calculator.py만 돌려서 테스트가 가능하다. 이렇게 되면 main.py에서는 테스트 코드를 돌리지 않고, 실제 작동하는 코드만 돌아가도록 코드를 유지할 수 있다.  


그런데, 문제는 여전히 존재한다. 

만약 main.py를 실행하면 어떻게 될까? 


결과를 보면, calculator.py의 테스트 코드가 실행되었음을 알 수 있다. 이는 우리가 의도했던 것과 사뭇 다르다. main.py를 돌릴 때는 테스트 코드를 돌리지 않고, 실제 코드가 동작해야 한다. 그런데 결과에서는 assert 구문이 실행되었음을 알 수 있다.


이는 main.py 내에서 calculator 모듈을 임포트 할 때, 파이썬이 내부적으로 파일을 실행하기 때문이다. 즉, 파이썬은 먼저 calculator.py를 실행하고, 이 중에서 calculate_sum과 calculate_min 함수를 main.py 내의 scope로 가져오는 것이다. 


위 문제는 __main__ 을 사용하면 간단하게 해결할 수 있다.


__main__은 함수가 아니라, 모듈의 이름을 의미한다. 파이썬은 임포트를 위해서 모듈을 읽어 들일 때, 해당 모듈 이름을 기억한다. 그래야 어떤 파일에서 코드를 가져왔는지 알 수 있기 때문이다. 이를 확인하려면 각 모듈 내에서 globals() 내의 __name__ 값을 확인해 보면 된다.


module1.py, module2.py, module3.py 함수에서 __name__ 값을 출력하도록 하고, 해당 모듈 3개를 main.py 에서 임포트했다. 그리고 main.py 내에서도 __name__을 출력해 보았다.

결과를 보면 module1.py의 이름은 module1, module2.py는 module2, module3.py는 module3로 지정되었음을 알 수 있다. main.py의 이름은 main이 아니라 __main__이다. __main__의 의미를 알아보기 전에 module1.py를 실행하면 어떻게 보이는지 확인해 보자.


module1.py를 직접 실행했더니 이름이 module1이 아니라, __main__임을 알 수 있다.


파이썬은 python 명령어로 실행하는 실제 파일 이름을 __main__으로 정한다. 그다음 모듈을 임포트 할 때는 모듈 이름을 지정해서 모듈 코드를 읽어 들인다. main.py에서 globals()에 포함된 심볼(symbol)을 보면 이를 확인할 수 있다.


이 점을 이용하면, 다음과 같이 코드를 수정하여 모듈 내에서만 테스트를 진행하도록 만들 수 있다.

 __name__이 만약 __main__이라면, 이는 python 명령어로 calculator.py를 직접 수행했다는 의미이다. 따라서, 이 경우에만 테스트 코드가 수행된다. 만약 main.py를 실행하면, calculator.py의 이름은 더 이상 __main__이 아니기 때문에, 해당 테스트 코드가 수행되지 않는다.


이는 AWS Lambda 코드를 작성할 때도 유용하게 사용할 수 있다. Lambda 코드는 내부적으로 핸들러 함수를 지정해서 사용해야 한다. 따라서, 내부 로직이 잘 동작하는지 테스트하려면 핸들러 함수를 명시적으로 수행해야 한다. 

https://docs.aws.amazon.com/ko_kr/lambda/latest/dg/python-handler.html



이 경우에도 __main__ 함수를 사용하면 손쉽게 원하는 테스트 코드만 수행하도록 만들 수 있다. (자세한 방법은 다음의 문서를 참조하기 바란다!) 이 방법을 활용하면, Lambda 함수로도 활용할 수 있지만, python 명령어를 통해서도 동일한 작업을 수행할 수 있도록 코드를 작성할 수 있다.



요컨대, __main__은 코드 진입점에 해당하는 파일을 지칭함으로써 실제 실행되는 파일이 무엇인지 나타내기 위한 특별한 모듈 이름이다. __name__ 변수 값이 __main__으로 지정되는 경우를 별도로 지정하면, 라이브러리로 사용하는 경우와 직접 모듈을 실행하는 경우로 나누어 코드를 작성할 수 있다. 

작가의 이전글 [Python] Iterable & Iterator
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari