C.W.K.
Stream
Lesson 04 of 06 · published

Context Manager — with / __enter__ / __exit__

~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 문 — 보장된 정리

with open(path) as f: 가 파일 열고 블록 빠져나갈 때 닫힘 보장 — 예외 여부 무관. 메커니즘 — with 다음 객체가 *context manager*, Python 이 진입 시 __enter__, 빠질 때 __exit__ 호출. 정리가 핵심 use case 지만 유일 X — "설정, 무관하게 해체" 필요한 모든 게 context manager.

프로토콜 — __enter__ 가 리소스 반환, __exit__ 가 정리

클래스가 __enter__(self) (`as` 로 바인딩될 값 반환) + __exit__(self, exc_type, exc_value, tb) (정리, 예외 있으면 정보 받음) 정의로 context manager. __exit__ 가 truthy 반환하면 예외 억제, falsy / None 이면 전파.

with 안에 여러 컨텍스트

with open(a) as fa, open(b) as fb: 가 둘 다 열고 닫음. 문법이 임의 중첩 평탄히 처리. 순서 중요 — 왼쪽에서 오른쪽 진입, 오른쪽에서 왼쪽 빠져나옴. 두 번째 open 이 raise 해도 첫 파일은 깨끗히 닫힘.

context manager 가 대체하는 거

try: ... finally: cleanup() 였던 모든 거. 파일 핸들, 락, DB 트랜잭션, 임시 chdir, stdout 리다이렉트, 연결 열기. finally 패턴 맞아 — context manager 패턴은 더 idiomatic, 더 재사용 가능, 덜 에러 prone 한 spell.

원칙: try: ... finally: cleanup() 짜고 있는데 정리 로직 재사용 가능 — context manager 짜. 다음 호출자 (미래의 자신) 가 기억할 필요 없이 자동으로 정리.

Code

클래스 기반 context manager·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
with 안에 여러 컨텍스트·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__ 가 truthy 반환·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("이 줄 여전히 실행 (X — try 안의 raise 후엔 안 닿음, 근데 with 후엔 실행)")

# contextlib.suppress 가 대략 이거 — 직접 짜는 대신 그거 써
with as 정리 패턴 — try/finally 대체·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

클래스 기반 context manager ChDir(path)with 블록 안에서 cwd 임시 변경, 빠질 때 복원 (예외 raise 되어도). (os.getcwd() + os.chdir() 친구). 블록 안에서 다른 디렉토리 진입, 빠질 때 os.getcwd() 가 시작점으로 — 안쪽 블록이 raise 해도 — 확인.

Progress

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

댓글 0

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

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