|

파이썬 with context manager 이해하기: 파일을 자동으로 닫는 이유

파이썬 with context manager 파일 close 대표 이미지
with 문은 시작과 정리가 짝을 이루는 작업을 안전하게 감싸는 문법입니다.

with context manager는 Python에서 파일, 락, DB 세션처럼 열고 닫는 작업을 안전하게 다룰 때 쓰는 문법입니다. `with open(…) as f:`는 파일을 자동으로 닫기 위해 자주 사용됩니다.

핵심은 시작해야 하는 작업과 반드시 정리해야 하는 작업을 한 블록에 묶는 것입니다. 이 글은 Python 공식 문서의 with 문과 context manager protocol을 기준으로 동작 흐름을 정리합니다.

파이썬 with 문과 context manager 요약 카드
context manager는 들어갈 때 __enter__, 나올 때 __exit__가 호출되는 구조입니다.

with context manager가 필요한 이유

파일을 열면 닫아야 합니다. DB 연결을 만들면 반환하거나 종료해야 합니다. 락을 잡으면 풀어야 합니다. 이런 작업은 시작과 정리가 항상 짝을 이룹니다.

file = open("memo.txt", "r", encoding="utf-8")
text = file.read()
file.close()

문제는 중간에 예외가 발생하면 `close()`까지 도달하지 못할 수 있다는 점입니다. 그래서 정리 코드는 보통 `finally`에 둡니다.

try finally와 with 문

file = open("memo.txt", "r", encoding="utf-8")
try:
    text = file.read()
finally:
    file.close()

이 코드는 안전하지만 매번 쓰기에는 길고 반복이 많습니다. `with` 문은 이런 시작과 정리 패턴을 더 읽기 쉽게 표현합니다.

with open("memo.txt", "r", encoding="utf-8") as file:
    text = file.read()

with 블록을 벗어나면 예외 여부와 상관없이 정리 동작이 실행됩니다. 파일 객체의 경우 close가 호출됩니다.

context manager란 무엇인가

context manager는 `with` 문과 함께 동작하는 객체입니다. 블록에 들어갈 때 `__enter__`가 호출되고, 블록을 나갈 때 `__exit__`가 호출됩니다.

class SimpleContext:
    def __enter__(self):
        print("enter")
        return self

    def __exit__(self, exc_type, exc, traceback):
        print("exit")

with SimpleContext() as ctx:
    print("inside")

`as ctx`에 들어가는 값은 `__enter__`의 반환값입니다. `__exit__`는 예외 정보도 받을 수 있어 정리와 예외 처리 정책을 함께 둘 수 있습니다.

__exit__가 예외를 볼 수 있다는 뜻

with 블록 안에서 예외가 발생하면 `__exit__`에는 예외 타입, 예외 객체, traceback이 전달됩니다. `__exit__`가 True를 반환하면 예외를 삼킬 수 있지만, 보통은 신중해야 합니다.

def __exit__(self, exc_type, exc, traceback):
    if exc_type:
        print("예외가 발생했습니다:", exc)
    return False  # 예외를 밖으로 다시 전달

contextlib로 간단히 만들기

간단한 context manager는 `contextlib.contextmanager`로 만들 수 있습니다. `yield` 앞은 enter, `yield` 뒤는 exit 쪽 정리 코드처럼 읽을 수 있습니다.

from contextlib import contextmanager

@contextmanager
def managed_resource():
    print("준비")
    try:
        yield "resource"
    finally:
        print("정리")

with managed_resource() as value:
    print(value)

언제 with를 쓰면 좋을까

  • 파일 open과 close가 짝을 이룰 때
  • threading.Lock처럼 acquire와 release가 필요한 때
  • DB session이나 transaction 범위를 제한할 때
  • 테스트에서 임시 설정을 적용하고 되돌릴 때

실무 체크리스트

  1. 작업에 반드시 정리 단계가 있는지 확인한다
  2. 이미 context manager를 제공하는 객체인지 확인한다
  3. with 블록 안에는 자원을 사용하는 코드만 둔다
  4. __exit__에서 예외를 삼킬지 전달할지 명확히 정한다
  5. 여러 자원은 한 with 문 또는 중첩 with 문으로 범위를 좁힌다

정리

파이썬 with 문은 파일을 자동으로 닫는 편의 문법에서 끝나지 않습니다. 시작과 정리가 짝을 이루는 작업을 안전하게 감싸는 구조입니다.

Python 함수와 흐름 제어 문법은 파이썬 args kwargs 차이, 파이썬 decorator 정리, SQLAlchemy MissingGreenlet은 FastAPI에서 왜 자주 보일까와 함께 보면 좋습니다. 외부 기준은 Python Tutorial – Reading and Writing Files, Python Reference – The with statement, Python Data Model – Context Managers를 확인했습니다.

함께보면 좋은 글