프로그래밍 언어/Python

with와 @contextlib.contextmanager

JMDev 2023. 9. 20. 19:19

파이썬으로 작성된 소켓연결 코드를 보는 와중에

소켓연결할 때, with 접두사로 활용하는 모습들이 보였다.

혹은, @contextlib.contextmanager 라는 데코레이터를 붙힌 후, 해당 fn 를 with문으로 활용하는 문법들을 보면서,

대체 with를 왜 쓰는것이고, 무엇을 하는 역활인지 궁금했고 찾아보았다.

 

with 문은 Python의 컨텍스트 관리 프로토콜을 사용하는 문법이며, 주로 리소스 관리에 사용되며,

이를 통해 파일, 네트워크 연결, 데이터베이스 연결 등의 리소스를 안전하게 사용하고 정리할 수 있다고 한다.

with 문의 3단계로 걸쳐 실행된다
  1. 진입: with 블록에 진입할 때, 컨텍스트 관리자의 enter 메서드가 호출됩니다. 이 메서드는 필요한 리소스를 할당하거나 초기화할 수 있습니다.
  2. 블록 실행: with 블록 내의 코드가 실행됩니다.
  3. 퇴장: with 블록에서 나갈 때, 컨텍스트 관리자의 exit 메서드가 호출됩니다. 이 메서드는 리소스의 정리 작업을 수행합니다. 예를 들어, 파일을 닫거나 네트워크 연결을 종료하는 등의 작업을 수행할 수 있습니다.

 

with문은 실행과 마지막 타이밍에 실행되는데 이를 데코레이터로 정의할 수 있다.

아래는 with문의 형태를 구현 및 순서를 확인할 수 있는 코드이다

class SimpleContextManager:
    def __enter__(self):
        print("Entering the context!")
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        print("Exiting the context!")

with SimpleContextManager():
    print("Inside the with block!")

print("Outside the with block!")

'''
Entering the context!
Inside the with block!
Exiting the context!
Outside the with block!
'''

위 코드로 보아, with를 실행하면 해당 class의 __enter__  -> with 본문의 코드 -> __exit__ 순으로 진행된다.

 

결론적으로는 with는 실행과 마무리를 컨트롤하는 데코레이터를 구현하는 문법이며,

위에서 언급되었던 리소스 관리를 하는 작업과 같이 시작 이후에 마무리 종료까지 책임질 수 있는 유용한 문법이라고 생각든다.

 

with 문법에 대해 이해도가 충분히 생겼고, 그 다음에는 @contextlib.contextmanager라는 데코레이터인데

이 데코레이터를 찾게된 이유는 아래 코드를 보다가 뭐지 싶어서 확인해보기 시작했다.

@contextlib.contextmanager
    def session(self, lower, upper, secret):
        print(f'Guess a number between {lower} and {upper}!'
              f' Shhhhh, it\'s {secret}.')
        self.secret = secret
        self.send(f'PARAMS {lower} {upper}')
        try:
            yield
        finally:
            self._clear_state()
            self.send('PARAMS 0 -1')
            
   # 위와 같이 데코레이터를 붙혀진 이후에 사용되는 방식
   with client.session(1, 5, 3):
            results = [(x, client.report_outcome(x))
                       for x in client.request_numbers(5)]

우선 위 코드로만 추측해보자면, 특정함수가 with문으로 활용될 수 있게 도와주는 데코레이터로 보이는데

좀 더 자세하게 알기 위하여 해당 함수를 직접 열어서 확인해보았다.

"""@contextmanager decorator.

    Typical usage:

        @contextmanager
        def some_generator(<arguments>):
            <setup>
            try:
                yield <value>
            finally:
                <cleanup>

    This makes this:

        with some_generator(<arguments>) as <variable>:
            <body>

    equivalent to this:

        <setup>
        try:
            <variable> = <value>
            <body>
        finally:
            <cleanup>
    """

위와 같이 주석처리가 되어있어고, 자세한 설명보단 이 데코레이터를 어떻게 활용하는지에 대한 활용방법이 나와 있었다.

This make this -> 해당 데코레이터는 함수를 이렇게 만들어 준다라고 하는 것 같고,

equivalent to this -> 아래와 같이 구현해라 라는 의미로 해석된다

 

위 구현방식대로 구현 후에 contextmanager 데코레이터를 활용한다면 해당 함수를 with문으로 사용할 수 있는 문법이다.