Python

[Python] context manager - 리소스 관리

비번변경 2025. 1. 31. 11:55

개요

Python에서 파일을 다룰 때는 파일을 열고 닫는 작업이 필요하다.

file = open('somefile', 'w')
try:
    file.write('Hola')
finally:
    file.close()

일반적인 프로그래밍에서 연 파일은 반드시 닫는 작업을 해야 하는데, 명시적으로 close 함수를 호출하는 불편함을 해소하기 위해 with 문을 사용할 수 있다.

with open("asd.txt", "r") as file:
    lines = file.readlines()
    ...

이 때 with문을 context manager라고 한다. 그럼 대체 context manger라는 게 뭘까? 알아보자.

 

 

Context manager

Context Manger는 Python의 독특한 기능 중 하나로, 사전 조건과 사후 조건을 처리할 때 유용해 다양한 방면에서 사용할 수 있다.

 

사용 예시

  • 스레드 락 acquire/release
  • 파일 open/close
  • 데이터베이스 작업 예외 발생 여부에 따른 commit/rollback
  • 숫자 연산 후 소숫점의 precision 계산

원하는 타이밍에 리소스를 할당하고 제공하는 역할을 하기 때문에 with문은 가장 많이 사용하는 context manager 중 하나이다.

 

with문은 다음과 같이 이해할 수 있다. 아래 코드는 with문 내부를 의사코드로 간단히 나타낸 것이다.

# naive approach
VAR = EXPR
VAR.__enter__()
try:
    BLOCK
finally:
    VAR.__exit__()

with문을 통해 context manager로 진입하는데, 진입 시에는 __enter__를, 종료 시에는 __exit__ 메소드를 호출한다. 각각의 함수에서 필요한 작업을 처리하면 된다.

 

__enter__

with문이 실행됨과 동시에 context manager로 진입하면서 실행된다. 필요한 사전작업을 하고 필요한 객체를 return할 수 있다. 반환값이 있는 경우 with문의 as 키워드를 통해 해당 객체를 받아 추가적인 작업을 이어갈 수 있다.

 

__exit__

with 블럭을 나갈 때, context manager가 종료될 때 호출된다. 사용하지 않을 리소스를 정리하는 등의 작업을 할 수 있다. 반환값은 필수가 아니지만 예외가 발생했을 때 False를 반환하여 잠재적으로 발생한 예외를 전파시킬 수 있다.

 

 

구현

Python에서 Context Manager를 구현하는 방법은 여러가지지만 대표적으로 매직 메서드를 구현하는 방법, 그리고 contextlib를 사용하는 방법을 주로 사용하는 것 같다. 이번 글에서는 매직 메서드를 구현하는 방향으로 알아본다.

 

Context Manager를 구현하기 위해서는 클래스에 __enter__, __exit__ 메서드를 구현해야 한다. 아래 예시는 context manager 진입 시 리스트를 생성하고, 종료 시 리스트의 내용을 호출하는 코드이다. 

class ListManager:
    def __enter__(self):
        self.list = []
        return self.list

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(self.list)

__exit__ 메서드의 매개변수는 컨텍스트에서 벗어나게 만든 예외를 기술하는데 사용된다.

 

구현한 클래스를 사용하면 다음과 같다.

if __name__ == '__main__':
    with ListManager() as lm:
        lm.append(1)
        lm.append(2)

with문 내에서 print 함수를 사용하지 않았음에도, with문을 빠져나가면서 __exit__ 메서드가 호출되며 리스트의 원소를 출력하는 모습을 확인할 수 있다.

 

 

참고 문서

https://docs.python.org/ko/3/library/contextlib.html

https://ddanggle.gitbooks.io/interpy-kr/content/ch24-context-manager.html

https://good.oopy.io/clean-code/context-manager

https://velog.io/@fregataa/Python3-Context-manager