본문 바로가기
C.W.K.
Stream
Lesson 04 of 06 · published

컨텍스트 관리자 — 자원의 수명을 with로 묶기

~20 min · context-manager, with, enter, exit, cleanup

Level 0호기심
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete

with 블록이 끝나면 정리도 끝나야 해

컨텍스트 관리자는 진입 시 __enter__, 이탈 시 __exit__를 호출해 예외가 나도 정리를 보장해. enter의 반환값이 as 이름에 묶이고, exit가 참을 돌려주면 예외를 억제해.

여러 자원은 들어간 반대 순서로 나온다

한 with에 여러 컨텍스트를 쓰면 왼쪽부터 들어가고 오른쪽부터 정리해. 두 번째 진입이 실패해도 이미 들어간 첫 자원은 닫혀.

파일, 잠금, 트랜잭션, 임시 작업 디렉터리처럼 “준비하고 반드시 되돌리기”가 반복된다면 try/finally를 재사용 가능한 수명 경계로 옮겨.

Code

클래스로 만드는 컨텍스트 관리자·python
class Timer:
    def __enter__(self):
        import time
        self.start = time.perf_counter()
        return self

    def __exit__(self, exc_type, exc_value, tb):
        import time
        elapsed = time.perf_counter() - self.start
        print(f"경과: {elapsed*1000:.2f}ms")
        # None / False — 예외 전파
        return False

with Timer() as t:
    sum(range(1_000_000))
# 경과: 12.34ms
여러 컨텍스트의 진입과 정리 순서·python
import contextlib, io

# 두 파일 — 둘 다 깨끗히 닫힘
fa = io.StringIO("hello")
fb = io.StringIO("world")

with fa, fb:                 # 둘 다 컨텍스트 관리, 빠질 때 닫힘
    print(fa.read(), fb.read())

# 오른쪽에서 왼쪽 종료 순서 — fb 먼저 닫힘, 그 다음 fa.
# fb 의 __enter__ 가 raise 해도 fa 의 __exit__ 실행.
__exit__가 예외를 억제하는 경우·python
class Suppress:
    def __init__(self, *types):
        self.types = types

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, tb):
        return exc_type is not None and issubclass(exc_type, self.types)
        # truthy => 예외 억제

with Suppress(ValueError):
    int("숫자 아님")              # ValueError 억제
    print("이 줄은 실행되지 않음 — raise 뒤에는 닿지 않고, with 다음 줄부터 실행")

# contextlib.suppress 가 대략 이거 — 직접 짜는 대신 그거 써
try/finally를 with 규약으로 옮기기·python
# 옛 스타일 — 수동 정리
f = open("data.txt")
try:
    contents = f.read()
finally:
    f.close()

# 새 스타일 — 자동
with open("data.txt") as f:
    contents = f.read()
# f 닫힘 — 예외 여부 무관

External links

Exercise

with 블록 동안 작업 디렉터리를 바꾸고 나올 때 원래 위치로 돌리는 ChDir(path)를 만들어. 블록 안에서 예외가 나도 os.getcwd()가 시작 위치로 돌아오는지 확인해.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.