본문 바로가기

Studying/Python

3. Context manager

우리가 코드를 통해 파일을 열고 내용을 작성해본다고 가정해보자.

 

위의 코드가 아주 보편적이고 일반적인 방법이다.

 

파일을 열고 작업을 끝낸 후에는 file.close( )를 통해 직접 닫아줘야한다.

 

이 때, 많은 작업량 중 오류가 발생하여 file.close( )가 실행되지 않는 문제가 발생할 수 있다.

 

이런 문제점을 해결하기 위한 첫번째 방법은 try, finally 키워드를 사용하는 것이다 .

 

이 방법은 오류가 발생해도 최종적으로는 파일을 닫을 수 있다. 

 

이보다 간편하고 더 많은 기능을 허용하는 방법이 있다.

 

바로 context manager 의 대표적인 예시 with문을 사용하는 방법이다. 

 

단 두 줄짜리 코드는 위의 내용과 정확히 일치하게 작동한다. 

 

with 구문안에 finally와 close의 의미가 내부적으로 존재하기 때문에 굳이 닫아주지 않아도 편리하게 사용가능하다.

 

context manager는 원하는 타이밍에 정확하게 리소스를 할당, 제공, 그리고 반환하는 역할을 하고,

 

with 문 이외에도 널리 사용되고 있다. 

 

이제부터, class를 이용하여 context manager를 만들고 적용하는 방법을 이야기해보도록 하자.  

 


우리가 context manager를 생성하는 방법에는 크게 2가지가 있다.

 

첫 번째는, class 내부에 직접 special method라고 불리는 __enter__과 __exit__을 사용하는 방법이다. 

 

( 선언된 class 내부에 __enter__와 __exit__가 있으면 context manager을 구현하려 했구나 생각하자 )

 

방법은 다음과 같다. 

 

여기서 __exit__ 메소드는 예외 발생시, 예외 처리 위한 exc_type, value, trace_back 3개의 변수를 인자로 받는다. 

 

def __exit__(self, error type, error value, trace_back) 

 

실제 사용할 경우, error를 강제 발생시켜도, context manager가 다 종료된 후, error 처리를 한다. 

 

강제로 error를 raise 했을 때의 결과

 

위의 terminal 창을 보면, (각 메소드마다 print 구문을 작성) context manager인 txtwriter가 exit까지 된 후,

 

error 처리를 한 것을 확인 할 수 있다. 

 

만약, 위 그림처럼 error 발생된 것을 나타내고 싶지 않을 때는, exit 메소드에 return 값으로 True를 주면 된다. 

 

exit 후, error에 대해 print만 실행 후, error 처리를 하지 않음 (error를 수정해야할 경우엔  쓰지 말기)


두 번째, 방법은 contextlib을 import한 후, decorator과 generator 개념을 활용하는 것이다. 

 

contextlib 모듈에는 generator를 context manager로 활용할 수 있게 만드는 decorator가 있고, 이를 import 할 경우,

 

코드를 좀 더 직관적으로 보이게 하며, 예외 처리할 때 편리하다는 장점이 있다. 

 

사용 방법을 살펴보자.

 

변수를 설정하여 open키워드를 활용하는 부분이 __enter__ 메소드라고 생각하자. 

 

yield 를 통해 generator 개념을 활용, 호출하는 곳으로 보낼 수 있게 만들고, 

 

close를 통해 __exit__를 구현한다고 생각하자.