~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 닫힘 — 예외 여부 무관
클래스 기반 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.