python) Context Manager

렁호·2022년 5월 11일
1
post-thumbnail

파일 관리

개발을 할 때에 개발자는 항상 주어진 리소스를 효율적으로 사용하도록 신경써야 한다.

아름다운 사람은 머문자리도 아름답다고 파일을 사용한 이후에는 사용하지 않은 것처럼 리소스(메모리)를 이전의 상태로 돌려놓고 가는 아름다운 프로세스가 필요하다.

python에서는 일반적으로 다음과 같이 사용한다.

f = open('test.txt', 'r', encoding='UTF8')

text = f.read()

print(text)

f.close()
나는 행복합니다~

워낙 심플한 로직이기 때문에 나쁜 코드라고 말할 순 없지만 pythonic한 대체코드가 있다면 사용하는 것이 좋을 것이다.

with

방금 전의 코드를 python with문을 사용하여 pythonic하게 만들어 줄 수 있다.

with open('test.txt', 'r', encoding='UTF8') as f:
    print(f.read())
나는 행복합니다~

처음 with문에 진입했을 때 파일을 열어주고 with문 스코프 안에 코드가 완료 된 이후 자동으로 파일을 닫아준다.

또한 중간에 에러가 발생한다면 이전 코드에서는 파일이 닫히지 않았을 수도 있지만 with문에서는 Close를 보장한다.

즉 다음의 코드와 동일한 기능을 한다.

f = open('test.txt', 'r', encoding='UTF8')
try:
    text = f.read()
    print(text)
finally:
    f.close()

위와 같이 파일을 열고 닫는 일 뿐만 아니라 특정 작업의 전후로 꼭 행여져야 하는 일을 도와주는 것을 Context Manager 라고 한다.

Context Manager는 효율적인 리소스 관리를 도와주며, 또한 불필요한 코드를 줄임으로서 좀 더 유지보수가 좋은 코드를 생산할 수 있도록 한다.

Magic Method

with 구문이 Context Manager의 기능을 할 수 있는 것은 특별한 Magic Method 덕분이다.

그러므로 해당 Magic Method만 잘 사용한다면 우리도 얼마든지 Context Manager를 생산해낼 수 있다는 뜻이다.

Context Manager class 만들기

class CustomContextManager:

    def __init__(self, name):
        self.name = name

    def __enter__(self):
        print('시작')

    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type:
            print(f'{exc_type,exc_val,exc_tb}')
        print('끝')

    def happy(self):
        print(f'{self.name}는 행복합니다')


cm = CustomContextManager('정호')

with cm:
    cm.happy()
시작
정호는 행복합니다
끝

__exit____enter__ magic method를 통해 Context Manager class를 간단하게 만들 수 있다.

__exit__ 을 잘보면 인스턴스 인자 외에 3개의 인자가 더 있는데 이것들은 예외처리를 도와주는 인자이다.

with cm:
    cm.happy()
    make_error = 2/0
시작
정호는 행복합니다
(<class 'ZeroDivisionError'>, ZeroDivisionError('division by zero'), <traceback object at 0x000002536EE46B00>)
끝

에러가 발생되더라도 다음과 같이 __exit__에서 에러를 핸들링 한 이후 내부 코드의 실행을 보장한다.

Context Manager function 만들기

from contextlib import contextmanager


@contextmanager
def custom_context_manager():
    print('시작')
    try:
        yield '메롱메롱'
    except Exception as e:
        print(f'error : {e}')
    finally:
        print('끝')


with custom_context_manager() as c:
    print(c)
    2/0
시작
메롱메롱
error : division by zero
끝

내장 라이브러리인 contextlibcontextmanager 데코레이터를 제너레이터에 사용함으로서 간단하게 함수형 컨텍스트 매니저를 만들 수 있다.

profile
식욕, 수면욕, 성욕 만땅

0개의 댓글