본문으로 바로가기

exit와 sys.exit은 무슨 차이일까 ?

category Language/Python 2022. 12. 27. 18:27
728x90
반응형

목차

    개요 

    exit와 sys.exit 두 가지 함수는 Python에서 프로그램을 종료시키기 위한 용도로 사용한다.

     

    그런데 왜 프로그램을 강제 종료하는 기능을 가지는 함수가 두 가지나 있을까? 

    1.  공통점 : 둘 다 SystemExit를 발생시킨다.

    공통점은 SystemExit Exception을 발생시킨다. 코드로 설명하자면 다음과 같다.

    # builtin - exit()
    try:
        exit(1)
    except SystemExit as e:
        print(e.args)
    
    # Result
    # (1,)
    
    import sys
    
    try:
        sys.exit(1)
    except SystemExit as e:
        print(e.args)
    
    # Result
    # (1,)

    어려운 코드가 아니니 구체적으로 설명할 부분이 없다. 각각의 특징을 알아보자.

     

    2.  exit() 함수는 뭐 하는 녀석일까?

     

    2.1 exit() 함수는 built-in이다.

    exit()는 파이썬을 설치하면 built-in으로 내장되어 있는 함수이다.

    https://docs.python.org/3/library/constants.html

    The site  module (which is imported automatically during startup, except if the -S command-line option is given) adds several constants to the built-in namespace. They are useful for the interactive interpreter shell and should not be used in programs.

    위는 파이썬의 공식 문서에서 인용했다.

     

    언급되어있듯이 exit()는 interactive shell 즉, Python Interpreter Shell에서 사용하라고 되어있다. 그런데 이게 조금 석연치 않았다. ‘공통점’에서도 나타났듯 exit도 SystemExit를 잡아서 처리하면 코드 레벨에서도 제어할 수 있는 것 아닌가?

     

    2.2 exit() 함수와 PEP0307

    조금 더 조사해보니 PEP 0307이라는 문서를 접하게 되었다.

    https://peps.python.org/pep-0370/ - "사용자별 사이트 디렉터리"

     

    exit() 함수는 site-package라는 패키지 안에서 가져온 함수이고 site-package는 환경에 따라 다를 수 있다는 내용이다.  

    python을 설치할 때 전역적으로 설치하는 경우가 있고 사용자가 환경을 따로 잡아서 설치하는 경우가 존재한다.

     

    이때 Python을 실행하는 위치에 따라 참조하는 site-package가 다르기 때문에 문제가 발생할 수 있다.

     

    즉, 환경에 따라 exit() 함수가 존재할 거라는 보장이 없다는 소리이다.

     

    2.3  exit() 테스트하기

    먼저 전역으로 설치한 파이썬을 실행한 뒤 exit()를 호출해 보자.

    $ python
    Python 3.10.8 (main, Oct 13 2022, 09:48:40) [Clang 14.0.0 (clang-1400.0.29.102)] on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import sys
    >>> sys.path
    ['',
    '/opt/homebrew/Cellar/python@3.10/3.10.8/Frameworks/Python.framework/Versions/3.10/lib/python310.zip',
    '/opt/homebrew/Cellar/python@3.10/3.10.8/Frameworks/Python.framework/Versions/3.10/lib/python3.10',
    '/opt/homebrew/Cellar/python@3.10/3.10.8/Frameworks/Python.framework/Versions/3.10/lib/python3.10/lib-dynload',
    '/opt/homebrew/lib/python3.10/site-packages']
    >>> exit()
    
    $

    전역적으로 설치된 python 설치 경로의 site-package를 참조하고 있는 것을 확인 수 있으며 이때 exit()를 호출하면 성공적으로 interpreter가 종료된다.

     

    다음은 -S 옵션을 줘서 site-package를 참조하지 않은 채로 interpreter를 실행해 보자.

    ╰─$ python -S
    Python 3.10.8 (main, Oct 13 2022, 09:48:40) [Clang 14.0.0 (clang-1400.0.29.102)] on darwin
    >>> import sys
    >>> sys.path
    ['',
    '/opt/homebrew/Cellar/python@3.10/3.10.8/Frameworks/Python.framework/Versions/3.10/lib/python310.zip',
    '/opt/homebrew/Cellar/python@3.10/3.10.8/Frameworks/Python.framework/Versions/3.10/lib/python3.10',
    '/opt/homebrew/Cellar/python@3.10/3.10.8/Frameworks/Python.framework/Versions/3.10/lib/python3.10/lib-dynload']
    >>> exit()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    NameError: name 'exit' is not defined
    >>>

    site-packge를 참조하고 있지 않으니 exit가 defined 되어있지 않고 있다는 Error를 출력한다.

     

    3. sys.exit() 함수는?

    sys.exit() 함수를 찾아보니 이 함수의 특징을 다음과 같이 설명한다.

    1. sys.exit() 함수는 sys 모듈을 import 해서 사용한다.
    2. exit()와 똑같이 SystemExit을 일으킨다. 그러나 exit()는 반대로 program 혹은 production 코드 안에서 동작하도록 디자인되었다.


    여기서 program 코드 안에서 동작도록 디자인 되었다는 것이 어떤 뜻인지 궁금했는데 이는 sys.exit()를 사용하려면 sys 모듈을 import 해야만 하니 built-in으로 사용하는 exit()의 문제(site-package 참조문제)가 일어나지 않을 것임을 의미했다.

     

    4. exit를 호출하여 발생할 수 있는 문제

    exit()와 sys.exit()를 알아봤으니 다음 코드를 살펴보자.

    class AException(Exception): ...    
    
    SOME_VAR = "THIS TEXT PRINTABLE?"
    
    def ex():
        # EOFError가 발생하면 어떻게 될까?
        try:
            print('1')
            a = input("text: ")  # Exepect EOFError
            if a:
                raise AException()
        except AException:
            print("AException")
    
        return False
    
    if __name__ == '__main__':   
        try:
            ex = ex()
        except:
            print("except")
            exit(1)
        finally:
            if ex:
                print(SOME_VAR)

    이 예제는 finally 구문을 통해 SOME_VAR를 출력할 수 있는가? 를 물어본다. 언뜻보면 사용자로부터 어떤 입력이든 입력을 받게 되면 AException()을 일으켜 main의 except syntax에서 무조건적으로 종료시키는 듯하다. 그러므로 finally까지 도달하는 경우는 있을 수 없어 보인다.

     

    하지만 ex() 함수에서 정의되지 않은 에러 즉 EOFError가 발생하면 어떻게 될까? EOFError는 ex() 함수에서 정의되지 않은 Exception이다. 그러므로 이를 처리하는 케이스가 없기 때문에 finally Synax를 타게 되므로 SOME_VAR에 지정된 문자열을 출력할 수 있게 된다.

     

     


    안녕하세요 jako입니다.

    해당 글을 통해 유용한 정보를 얻으셨길 바랍니다.

    경험과 지식의 공유를 통해 조금 더 양질의 정보를 생성하기위한 뉴스레터를 만들었습니다.

    블로그에는 기재되지 않을 유용한 정보 또한 뉴스레터에 담아 발행하고자합니다. 

     링크를 클릭하여 뉴스레터를 구독해주세요.

    양질의 정보와 함께 찾아뵙겠습니다.


     

     

    728x90
    반응형