Python/파이썬 오픈소스 배포

Context Manager Annotation

monstro 2025. 6. 27. 14:49
728x90
반응형

- 개요

이전까지 클래스의 형태로 Context Manager를 만들어 사용했다

클래스를 만들어 Context Manager를 구현하는 방식은 예외처리를 정교하게 구현할 수 있지만,

만드는 방식이 복잡하여 실질적으로 사용하기는 어렵다

 

이런 상황에서 함수를 통해 Context Manager를 구현하면 덜 복잡한 방법으로 구현하는 것이 가능하다

함수를 통해 구현하므로 Decorator를 사용하면 훨씬 효율적이다

Decorator함수를 직접 수정하지 않고 기능을 추가하고자 할 때 사용할 수 있다

 

또 Decorator의 경우, annotation을 통해 훨씬 더 쉽게 사용할 수 있다

그러므로 contextlib 모듈을 사용하여 제공되는 Decorator를 이용한 Context Manager 함수를 구현해본다

 

1) Context Manager 함수의 구현

import contextlib

@contextlib.contextmanager
def my_file_writer(file_name, method):
    f = open(file_name, method)
    yield f   # __enter__
    f.close() # __exit__

with my_file_writer('TestFile4.txt', 'w') as f:
    f.write('Context Manager Test4.\nContextlib Test4.')

 

contextlib 모듈을 import하여 제공되는 contextmanager 데코레이터를 사용할 수 있다

@ 연산자를 이용한 annotation 형태decorator를 사용하면

함수를 호출할 때, decorator의 기능을 추가하여 사용한다

 

Context Manager 함수 my_file_writer에서는 파일 이름동작 방식을 인자로 받아 동작한다

이때 함수 내부에서 yield 문을 통한 __enter__ 메서드를 구현하고

파일 객체를 close하여 __exit__ 메서드를 구현한다

 

 

Context Manager 함수를 with 함수를 통해 실행하면

수행한 결과에서 파일이 문제없이 작성된 것을 확인할 수 있다

 

2) Context Manager 함수의 응용

import contextlib
import time

@contextlib.contextmanager
def ExecutionWithTimer(msg):
    start = time.monotonic()
    try:
        # __enter__
        yield start
    except Exception as e:
        print(f'Error Ocurred : {msg} {e}')
        raise
    else:
        # __exit__
        print(f'Total time of {msg} : {time.monotonic() - start}')

with ExecutionWithTimer("Hello from decorator") as et:
    print(f'Start at {et}')
    for i in range(30000000):
        pass

 

이전에 클래스로 만든 순수 실행 시간을 구하는 Context Manager 예제를 함수 형태로 구현하였다

1)의 예제와 동일하게 annotation을 사용하여 decorator를 함수에 적용한다

 

try 문에서 yield 함수를 통해 __enter__ 메서드를 구현하였고,

except 문을 통해 예외를 처리한다

마지막으로 else 문에서 print 함수를 호출하는 것으로 __exit__ 메서드를 구현하였다

 

 

with 함수를 통해 Context Manager 함수를 호출함으로써

msg를 설정하고 3000,0000초 후에 출력하기까지 걸린 시간을 측정할 수 있다

 

...

with ExecutionWithTimer("Hello from decorator") as et:
    print(f'Start at {et}')
    for i in range(30000000):
        pass
    raise Exception("Forced Error")

 

위와 같이 예외를 발생시키도록 코드를 수정한다면

 

 

메세지를 출력 (__exit__)하지 못하고 에러를 출력하는 것을 확인할 수 있다

728x90
반응형

'Python > 파이썬 오픈소스 배포' 카테고리의 다른 글

Getter 메서드와 Setter 메서드  (0) 2025.07.01
언더스코어(_)의 사용  (0) 2025.06.30
Context Manager (2)  (0) 2025.06.24
Context Manager (1)  (0) 2025.06.24
객체의 복사  (0) 2025.06.23