
파일, 데이터베이스 연결, 네트워크 세션, 잠금 객체는 사용이 끝나면 반드시 정리해야 합니다. 정상 실행만 생각해 close를 마지막 줄에 호출하면 중간 예외나 조기 return 때문에 정리 코드가 실행되지 않을 수 있습니다. 파이썬의 컨텍스트 관리자와 with 문은 진입과 종료 동작을 하나의 계약으로 묶어 성공과 실패에 관계없이 자원이 반환되도록 보장합니다.
with 문이 해결하는 문제
파일을 직접 open한 뒤 try/finally에서 닫는 코드는 올바르지만 반복적입니다. with open(path, encoding='utf-8') as file을 사용하면 블록을 벗어날 때 자동으로 파일이 닫힙니다. 예외가 발생하거나 함수가 중간에 return해도 종료 처리가 실행됩니다. 자원의 사용 범위가 들여쓰기로 명확하게 보인다는 점도 큰 장점입니다.
__enter__와 __exit__ 이해하기
클래스 기반 컨텍스트 관리자는 __enter__에서 자원을 준비하고 with의 as 뒤에 전달할 값을 반환합니다. __exit__는 블록이 끝날 때 호출되며 예외 형식, 예외 객체, traceback을 전달받습니다. 종료 메서드가 참 값을 반환하면 예외가 억제되므로, 복구할 이유가 없다면 거짓 값을 반환하거나 반환을 생략해 원래 오류가 호출자에게 전달되게 합니다.
실무 원칙: 자원 정리와 오류 숨기기는 다른 책임이므로, 컨텍스트 관리자가 예상하지 못한 예외를 조용히 삼키지 않게 해야 합니다.
contextlib.contextmanager로 간결하게 만들기
작은 컨텍스트 관리자는 @contextmanager를 붙인 제너레이터 함수로 만들 수 있습니다. yield 앞에서 준비하고 yield 뒤의 finally에서 정리합니다. yield는 정확히 한 번 실행돼야 하며, 정리 코드가 실행되도록 try/finally 구조를 사용합니다. 함수가 짧고 흐름이 단순할 때 유용하지만 상태가 복잡하거나 여러 메서드가 필요하면 클래스가 읽기 좋을 수 있습니다.
구현 체크포인트
- 자원 획득이 실패했을 때 정리할 대상이 있는지 구분합니다.
- 일부 자원만 준비된 상태도 안전하게 해제합니다.
- 종료 중 오류가 원래 오류를 덮지 않게 기록 정책을 정합니다.
- 컨텍스트 객체를 블록 밖에서 재사용하지 않습니다.
- 중첩 순서와 해제 순서가 반대임을 확인합니다.
데이터베이스 트랜잭션에 적용하기
트랜잭션 컨텍스트는 블록이 성공하면 커밋하고 예외가 발생하면 롤백할 수 있습니다. 다만 연결 객체 자체의 with 동작은 드라이버마다 다르므로 공식 문서를 확인해야 합니다. 내부 함수가 임의로 커밋하면 상위 업무의 원자성이 깨질 수 있어 트랜잭션 경계는 서비스 계층에서 관리하는 편이 좋습니다. 외부 API 호출을 기다리는 동안 트랜잭션을 오래 열어 두지 않습니다.
여러 자원을 ExitStack으로 관리하기
실행 중에 열 파일 개수가 결정되거나 선택 옵션에 따라 자원이 달라진다면 with 문을 미리 중첩하기 어렵습니다. contextlib.ExitStack은 동적으로 컨텍스트를 등록하고 마지막에 들어온 것부터 역순으로 정리합니다. 여러 파일을 모두 성공적으로 연 뒤 처리하거나, 중간 실패 시 이미 연 파일만 닫는 흐름에 적합합니다.
임시 상태를 되돌리는 용도
컨텍스트 관리자는 파일 외에도 잠금, 임시 디렉터리, 환경 설정, 로깅 문맥에 사용할 수 있습니다. 테스트에서 현재 작업 디렉터리를 잠시 바꾸거나 로그에 요청 ID를 넣었다가 원래 상태로 돌릴 수 있습니다. 전역 상태를 변경한다면 동시에 실행되는 다른 작업에 영향을 줄 수 있으므로 스레드와 비동기 실행 환경을 고려해야 합니다.
비동기 컨텍스트 관리자
비동기 연결의 준비와 종료에 await가 필요하면 async with와 __aenter__, __aexit__를 사용합니다. contextlib의 asynccontextmanager도 활용할 수 있습니다. 비동기 블록이 취소되더라도 연결 반환과 잠금 해제가 수행되게 finally를 구성하고, 정리 작업 자체가 무한히 기다리지 않도록 제한 시간을 검토합니다.
다른 언어와 연동할 때의 경계
파이썬 컨텍스트가 닫혔다고 원격 시스템의 작업까지 자동 취소되는 것은 아닙니다. JavaScript나 Java 서비스에 HTTP 요청을 보낸 뒤 응답 전에 연결을 닫아도 서버 작업이 계속될 수 있습니다. 요청 ID와 멱등성 키, 취소 API를 별도로 설계해야 합니다. 데이터베이스 커밋 여부가 모호한 네트워크 실패도 거래 ID로 상태를 조회할 수 있어야 합니다.
테스트 순서
- 정상 완료 후 자원이 닫혔는지 확인합니다.
- 블록 중간에 예외를 발생시켜 정리 여부를 검사합니다.
- 조기 return과 사용자 취소 상황을 시험합니다.
- 일부 자원 획득 실패 후 이미 연 자원이 닫히는지 봅니다.
- 중첩 자원이 역순으로 정리되는지 확인합니다.
- 롤백 실패처럼 종료 단계의 오류도 테스트합니다.
- 비동기 취소 중 연결 풀이 누수되지 않는지 측정합니다.
컨텍스트 관리자는 코드 줄 수를 줄이는 문법 이상의 도구입니다. 자원의 생성과 정리, 트랜잭션의 성공과 실패를 같은 위치에 정의해 호출자가 안전한 범위를 자연스럽게 지키도록 만듭니다. 자원 수명과 예외 정책을 먼저 정한 뒤 with 문으로 표현하면 운영 중 누수와 잠금 문제를 크게 줄일 수 있습니다.
한 줄 요약: 파이썬 컨텍스트 관리자는 자원 획득과 해제를 한 계약으로 묶고 예외·취소 상황에서도 정리를 보장하도록 설계해야 합니다.