contextlib — with 문 컨텍스트 유틸리티
contextlib — with 문 컨텍스트 유틸리티
(소스: Lib/contextlib.py)
이 모듈은 with 문과 관련된 공통 작업을 위한 유틸리티를 제공해요. 자세한 내용은 "Context Manager Types"와 "With Statement Context Managers"를 함께 보세요.
본문
유틸리티
class contextlib.AbstractContextManager:__enter__()와__exit__()을 구현하는 클래스들의 추상 기본 클래스.__enter__()의 기본 구현은self를 반환하고,__exit__()은 기본 None을 반환하는 추상 메서드예요. (3.6 추가)class contextlib.AbstractAsyncContextManager:__aenter__()와__aexit__()을 구현하는 클래스들의 추상 기본 클래스.__aenter__()의 기본 구현은self를 반환하고,__aexit__()은 기본 None을 반환하는 추상 메서드예요. (3.7 추가)
@contextlib.contextmanager
with 문 컨텍스트 매니저용 팩토리 함수를, 클래스를 만들거나 별도의 __enter__()·__exit__() 메서드를 만들지 않고 정의할 수 있게 해 주는 데코레이터예요. 많은 객체가 with 문을 네이티브로 지원하지만, 때로는 그 자체로 컨텍스트 매니저가 아니고 contextlib.closing에 쓸 close() 메서드도 구현하지 않은 리소스를 관리해야 해요. 올바른 리소스 관리를 보장하는 추상 예시를 볼게요.
from contextlib import contextmanager
@contextmanager
def managed_resource(*args, **kwds):
resource = acquire_resource(*args, **kwds)
try:
yield resource
finally:
release_resource(resource)
이렇게 사용할 수 있어요.
>>> with managed_resource(timeout=3600) as resource:
... # Resource is released at the end of this block,
... # even if code in the block raises an exception
데코레이트된 함수는 호출 시 generator-iterator를 반환해야 해요. 이 iterator는 정확히 하나의 값을 yield해야 하고, 그 값이 with 문의 as 절 타깃에 바인딩돼요. generator가 yield하는 지점에서 with 문 안에 중첩된 블록이 실행되고, 블록을 빠져나온 후 generator가 재개돼요. 블록에서 처리되지 않은 예외가 발생하면 generator 안의 yield가 일어난 지점에서 다시 발생해요. 그래서 try…except…finally 문으로 오류를 잡거나 정리를 보장할 수 있어요. 예외를 완전히 억제하기보다 단지 로그를 남기거나 어떤 동작을 하기 위해 잡았다면 generator는 그 예외를 다시 발생시켜야 해요. 그렇지 않으면 컨텍스트 매니저가 with 문에 예외가 처리됐다고 알리고 with 문 바로 다음 문장에서 실행이 재개돼요.
@contextmanager는 ContextDecorator를 사용하므로 만든 컨텍스트 매니저를 with 문뿐 아니라 데코레이터로도 쓸 수 있어요. 데코레이터로 쓰면 각 함수 호출 시 새 generator 인스턴스가 암시적으로 생성돼요(이로써 "원샷" 컨텍스트 매니저가 데코레이터로 쓰이기 위해 필요한 여러 번 호출을 지원). (3.2에서 ContextDecorator 사용)
@contextlib.asynccontextmanager
@contextmanager와 비슷하지만 비동기 컨텍스트 매니저를 만들어요. async with 문용 비동기 컨텍스트 매니저 팩토리 함수를, 클래스를 만들거나 별도의 __aenter__()·__aexit__() 메서드를 만들지 않고 정의할 수 있어요. 비동기 generator 함수에 적용해야 해요.
기타 유틸리티
contextlib.closing(thing):thing.close()를 블록 종료 시 호출하는 컨텍스트 매니저를 반환. 닫힘을 지원하지만 컨텍스트 매니저가 아닌 것을 with 문으로 다룰 때 유용.contextlib.aclosing(thing): 비동기 버전.__aexit__에서await thing.aclose()를 호출.@contextlib.asynccontextmanager,contextlib.nullcontext(enter_result=None): 아무 일도 하지 않는 컨텍스트 매니저. 무엇을 해야 할지 결정할 수 없을 때 특정 자원을 선택적으로 사용하는 데 유용.enter_result를 as 절에 반환.@contextlib.suppress(*exceptions): 명시된 예외를 억제하는 컨텍스트 매니저. with 블록에서 그 예외 중 하나가 발생하면 정상 흐름을 계속.@contextlib.redirect_stdout(new_target)/@contextlib.redirect_stderr(new_target): 블록 동안sys.stdout/sys.stderr를new_target으로 임시 리다이렉트.class contextlib.ContextDecorator: 컨텍스트 매니저를 데코레이터로도 쓸 수 있게 해 주는 기본 클래스.class contextlib.ExitStack: 다른 (동적) 컨텍스트 매니저와 정리 함수를 관리하는 스택. 프로토콜 처리, 한 문장에서 종료, 예외가 있으면__exit__에서 예외를 다시 발생시키는 등의 유연한 조합을 가능하게 해요.enter_context(cm),push(cm),callback(func, /, *args, **kwds),pop_all(),close()메서드 제공.class contextlib.AsyncExitStack: 비동기 버전.enter_async_context(cm)제공.
예제와 레시피
이 모듈의 예제·레시피 문서는 다음을 소개해요.
- 가변 개수의 컨텍스트 매니저 지원:
ExitStack가 컨텍스트 매니저 수가 가변적일 때 어떻게 쓰는지. __enter__메서드의 예외 잡기:ExitStack.push()등으로__enter__에서 발생한 예외를 처리.__enter__구현에서 정리:ExitStack.push로 자원 획득을 추적하고 실패 시 정리.- try-finally와 플래그 변수 대체:
@contextmanager나ExitStack로 정리를 단순화. - 컨텍스트 매니저를 함수 데코레이터로 사용하기:
ContextDecorator와@contextmanager조합. - 단일 사용·재사용·재진입 컨텍스트 매니저:
@contextmanager로 만든 매니저는 원샷이지만, 무한 생성기나 재진입 가능하게 만들 수 있는 방법. 재진입 컨텍스트 매니저는 이미 진입한 상태에서 다시 진입할 수 있고, 재사용 컨텍스트 매니저는 여러 번 사용할 수 있어요.