Search

with, Context Manager

대분류
언어
소분류
Python
유형
클래스
with
Context Manager
최종 편집 일시
2024/10/27 15:31
생성 일시
2024/07/19 05:13
15 more properties

with절

자원을 획득하고, 사용하고, 반납할 때 주로 사용 (파일 열/닫기, DB 사용, 네트워크 연결)
1.
자원을 획득/생성한다.
2.
자원을 사용한다.
3.
자원을 반납/소멸한다.
파일을 여는 경우 다른 프로세스를 위해 사용한 뒤 닫아주어야 한다. → try / except / finally 구문을 통해 구현이 가능하지만 with절로 하는 것이 낫다.
예외가 발생하는 케이스 및 탈출 조건을 만족하는 케이스에 대해서 리소스를 정리하는 코드가 중복으로 작성 → with절은 이런 불필요한 리소스를 with절 내에서만 엑세스가 가능하게 하고, 블록을 나가는 경우엔 어떤 이유든 간에 리소스를 해제하여 낭비를 막는 역할을 한다.

기본 구조

with 객체 [as 별칭]: block.. # 빠져나오면 종료
Python
복사

예시

파일을 읽고 종료하는 코드
f = open('myFile.txt', 'w', encoding='utf8') f.write("test") f.close()
Python
복사
with절을 사용한 코드
with open('myFile.txt', 'w', encoding='utf8') as f: f.write("test") # 여기서 open('myFile.txt', 'w', encoding='utf8')가 CM
Python
복사

Context Manager

with 문과 함께 사용할 메서드를 정의하는 객체
file = open('file.txt', 'r') try: content = file.read() finally: file.close() # 이랬던 코드가 with open('file.txt', 'r') as file: content = file.read() # 이렇게 간단해진다.
Python
복사
구현 방법
1.
Native Implementation
2.
conextlib.contextmanager
3.
contextlib.ContextDecorator

1. Native Implementation

__enter__ 및 __exit__ 메서드가 존재
자원의 설정 및 정리를 수동으로 처리하는 것은 오류 발생 가능성이 높아지기 떄문에 자동으로 관리해주는 Context Manager가 필요하다.
클래스로 활용도 높히기
class Hello: def __enter__(self): print('enter...') return self def sayHello(self, name): print('hello ' + name) def __exit__(self, exc_type, exc_val, exc_tb): print('exit...') with Hello() as h: h.sayHello("name") # 출력 결과 enter... hello name exit...
Python
복사
__enter__(self)
with블록 시작 시 호출
__exit__(self, exc_type, exc_val, exc_tb)
with 블록 종료 시 호출

2. conextlib.contextmanager

contextlib 내장 모듈의 contextmanager 데코레이터를 이용하는 방법
함수 리팩토링이 쉬워진다.
객체지향적으로 프로그램을 설계하면 아무 의미 없는 가짜 부모클래스를 만들어야하는 번거로움이 있다.
__enter__ == yield 이전 코드
__exit__ == yield 이후 코드
from contextlib import contextmanager @contextmanager def gen_process(): print('start of process') yield 'gen_process' print('end of process') with gen_process() as gp: print(f'processing {gp} ...')
Python
복사

3. contextlib.ContextDecorator

일종의 믹스(1번 + 2번)인 클래스로 데코레이터를 구현하기 위한 로직을 제공
process 함수와 process_decorator 데코레이터 사이의 독립성이 보장
as 등으로 무언가를 넘겨주는 작업도 없다.
불편할 수도 있지만 기능적으로 분리되고 접근을 제한하여 독립성을 보장하는 것은 좋은 특성
from contextlib import ContextDecorator class process_decorator(ContextDecorator): def __enter__(self): print('start of process') return self def __exit__(self, exc_type, exc_value, exc_traceback): print('end of process') @process_decorator() def process(): print('processing ...')
Python
복사

time.timer을 사용하여 실행시간 측정하기

import time class Timer: def __enter__(self): self.start = time.time() return self def __exit__(self, exc_type, exc_val, exc_tb): self.end = time.time() print(f'경과 시간: {self.end - self.start} 초')
Python
복사

with와 try-finally의 차이점

둘다 Python에서 리소스 관리에 사용
try-finally 블록
예외가 try 블록에서 발생했는지 여부에 관계없이 항상 실행되어야 하는 정리 코드를 지정할 수 있는 좀 더 낮은 수준의 구조
리소스의 설정을 관리하는 메커니즘을 제공하지 않음.
with 블록
리소스의 설정과 정리를 모두 처리
리소스 관리 로직을 클래스 내에서 캡슐화