[모던 Python 8편] Context Manager와 with문으로 자원 자동 정리하기

기존 파이썬 코드에서는 파일, 네트워크 소켓, DB 커넥션 등 자원 사용 후 수동으로 정리(닫기)해야 했습니다. 이를 위해 try-finally 블록을 사용했지만, 매번 이런 보일러플레이트를 작성하는 것은 번거롭고, 예외 발생 시 자원 반납 처리 누락 등의 문제가 생기기 쉬웠습니다.

Context Managerwith문을 사용하면 이러한 자원 정리 과정을 자동화하고, 코드 가독성과 안전성을 크게 향상시킬 수 있습니다.

이번 글에서는 기존 방식과 새로운 방식의 비교, Context Manager 개념, with문 사용 예제, 장단점을 살펴봅니다.

이전에는 어떻게 했을까?

try-finally를 통한 수동 자원 정리

f = open("data.txt", "r")
try:
    content = f.read()
finally:
    f.close()
  • 장점: 명시적으로 자원 사용 범위를 알 수 있음
  • 단점: 매번 try-finally 패턴 반복, 예외 처리 로직과 자원 반납 로직 혼재

Context Manager와 with문 도입

with문은 Context Manager 프로토콜(__enter__, __exit__)을 지원하는 객체를 사용할 때, 진입 시 __enter__()가 호출되고, 블록 종료 시(정상/예외 여부와 무관하게) __exit__()가 호출되어 자원을 자동 정리합니다.

with open("data.txt", "r") as f:
    content = f.read()

장점:

  • 보일러플레이트 감소: try-finally 없이도 자원 정리 자동 처리
  • 가독성↑: 자원 사용 범위가 with 블록으로 명확히 구분
  • 안전성↑: 예외 발생 시에도 exit가 호출되어 자원 반납 보장

커스텀 Context Manager 구현

직접 만든 클래스에도 __enter__, __exit__ 메서드를 정의하면 with문에서 사용 가능. 예:

class ManagedResource:
    def __enter__(self):
        print("Resource acquired")
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("Resource released")

with ManagedResource() as resource:
    print("Using resource")

출력:

Resource acquired
Using resource
Resource released

예외 발생 시에도 __exit__ 호출, 자원 정리 보장.

단점/주의사항

  • Context Manager는 자원 사용 범위를 명확히 제한하므로, 자원을 블록 밖에서 계속 사용하려면 별도 구조 고려 필요
  • 모든 상황에 with문이 적합한 것은 아니지만, 파일, 소켓, 락(lock), DB 커넥션 등 자원 사용 후 반납 필요 시 적합
  • Python 2에서는 contextlib 모듈의 contextmanager 데코레이터로 유사 기능 구현 가능, Python 3+에서 기본 지원

결론

  • 이전 방식: try-finally로 자원 정리, 보일러플레이트 증가, 예외 처리 시 코드 복잡
  • 새로운 방식: Context Manager와 with문으로 자원 반납 자동화, 가독성↑, 안정성↑
  • Pythonic하게 자원 관리 로직 단순화 가능

다음 글에서는 표준 라이브러리의 고급 함수나 도구(functools, itertools)를 통해 수작업 루프보다 더 간결하고 선언적으로 데이터를 처리하는 방식에 대해 알아보며, 코드 단순화와 성능 개선에 유용한 함수형 툴들을 살펴보겠습니다.

반응형