with 문은 「__enter__와 __exit__ 두 매직 메서드를 가진 객체」면 누구든 사용할 수 있습니다.
자기 클래스를 컨텍스트 매니저로 만들면 자기만의 자원 관리 패턴을 정의할 수 있습니다.
기본 형식.
class Timer: def __enter__(self): self.start = time.time(); return self; def __exit__(self, exc_type, exc_val, exc_tb): print(f"걸린 시간: {time.time() - self.start:.2f}초").
with Timer(): time.sleep(2).
— 「걸린 시간: 2.00초」 출력.
with 블록 안의 시간을 자동으로 측정하는 컨텍스트 매니저입니다.
__enter__는 with 블록에 들어갈 때 호출되어 「반환한 값이 as 뒤의 변수에 들어감」.
__exit__은 블록을 떠날 때 호출 — 정상이든 예외든 상관없이.
예외 정보가 인자로 들어와 오류를 가로챌 수도 있습니다.
더 간단한 방법: contextlib.contextmanager 데코레이터.
from contextlib import contextmanager.
@contextmanager; def timer(): start = time.time(); yield; print(f"걸린 시간: {time.time() - start:.2f}초").
with timer(): ...
— 함수 한 개로 컨텍스트 매니저 완성.
yield 위가 __enter__, 아래가 __exit__에 해당합니다.
활용 예시들.
일시적 디렉토리 변경 (chdir), 일시적 환경변수 설정, 트랜잭션 자동 커밋·롤백, 모의(mock) 객체 자동 복원.
「시작 시 무언가 변경, 끝날 때 원상 복귀」 패턴이면 모두 컨텍스트 매니저로 표현할 수 있습니다.
한 줄 요약
컨텍스트 매니저는 __enter__·__exit__ 두 메서드를 정의하면 만들 수 있고, 더 간단하게는 @contextmanager + yield로 함수로도 만들 수 있습니다.
더 알아볼 것
- __exit__의 예외 처리
- contextlib.suppress — 특정 예외 무시
- contextlib.ExitStack — 여러 컨텍스트 결합