Python

[Python] Context Manager 일반적으로 쓰이는 예시

UnoCoding 2023. 1. 31. 23:15

먼저 보는 Context Manager 예시 

일반 적인 사용 예시로는 아래와 같이 파일 Handler에 사용 된다.

with open('alice-in-wonderland.txt', 'rw') as infile:
    line = infile.readlines()
    do_something_more()

context manager을 사용하지 않는다면 try문으로 구현 해야 한다.

try:
    infile = open('alice-in-wonderland.txt', 'r')
    line = infile.readlines()
    do_something_more()
finally:
    infile.close()

또 다른 예시로는 Thread Lock가 있습니다.

 

lock을 acquire하면 해당 쓰레드만 공유 데이터에 접근할 수 있고, lock을 release 해야만
다른 쓰레드에서 공유 데이터에 접근할 수 있습니다.

a_lock = threading.Lock()

with a_lock:
    do_something_more()

thread lock을 풀어준느 코드를 집적 사용해야 하는 반명 Lock에는 __enter__ 와 __exit__가 있어 context manager로 구현이 가능 합니다.

a_lock.acquire()
try:
    do_something_more()
finally:
    a_lock.release()

 

Context Manager란?

 

__enter__와 __exit__ 매직 메서드로 구성 되어 있다. 예시는 다음과 같다.

import os


def strat_postgres():
    os.system("systemctl start postgresql")


def stop_postgres():
    os.system("systemctl stop postgresql")


class DBHandler:
    def __init__(self):
        self.db = None

    def __enter__(self):
        strat_postgres()
        return self.db

    def __exit__(self, exc_type, exc_val, exc_tb):
        stop_postgres()


if __name__ == "__main__":
    with DBHandler() as db:
        print(db)

 

with 문은 __enter__ 메서드를 호출하고 이 메서드가 무엇을 반환 하든 as 이후에 지정된 변수에 할당합니다.

 

__enter__ 함수가  먼저 호출이 되고 실행하려 하는 기능을 모두 실행 후 오류가 있던 없던 __exit__함수가 호출됩니다.

 

특히나 __exit__에 집중을 해 보자면 exc_type, exc_val, exc_tb 3개의 전달받은 매개 변수를 통해 에러에 대한 내용을 받아 볼 수 있습니다. 에러가 없을 경우 해당 값은 None을 반환 합니다.

 

class DBHandler:
    def __init__(self):
        self.db = None

    def __enter__(self):
        strat_postgres()
        return self.db

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(exc_type, exc_val, exc_tb)
        stop_postgres()


if __name__ == "__main__":
    with DBHandler() as db:
        raise Exception("Error")
<class 'Exception'> Error <traceback object at 0x0000024B5074E040>
Traceback (most recent call last):
  File "c:\Users\dhkim\Desktop\storeDrf\test.py", line 29, in <module>    raise Exception("Error")
Exception: Error

 

Context Manager를 구현 하기위한 다른 방법

 

__enter__와 __exit__ 매직 메서드로 구현 하는 것은 일반적인 방법이지만 유일한 방법은 아닙니다.

 

표준 라이브러리인 contextlib 모듈을 사용하여 보다 쉽게 구현 하실수 있습니다.

contextlib모듈은 context Manager를 구현하는데 도움이 되는 함수가 많습니다. 

 

이중 contextlib.contextmanager 데코레이터를 적용하면 함수의 코드를 context manager로 바꿀 수 있습니다.

하지만 함수의 조건은 제러레이터라는 특수한  함수의 형태이여야 합니다.

 

import contextlib
import os


def strat_postgres():
    os.system("systemctl start postgresql")

def stop_postgres():
    os.system("systemctl stop postgresql")

@contextlib.contextmanager
def db_handler():
    strat_postgres()
    yield
    stop_postgres()


with db_handler():
    db_handler()

 또한 데코레이터 형식으로도 구현이 가능합니다.

Django에서 쓰이는 Context Manager란?

포스팅을 통해 Django에서 쓰이는 Context Manager를 조금 정리했습니다.