티스토리 뷰

연습

Python ContextManager (with~)

onaeonae1 2024. 12. 27. 18:39

with ?

파이썬으로 코드 작성을 하다 보면 with ~ as ~ 구문을 마주하게 된다

 

이게 어떤 기능을 하고 어떤 원리에 의해 동작하는지 정리해보자

 

일단 다음과 같은 예시의 코드를 살펴보자

with open("example.txt", "w") as file:
    file.write("Hello, World!")
# 파일은 블록 종료 시 자동으로 닫힌다.

 

File Descriptor 같은 경우 write 후 바로 종료되어야 하는 상황에서 위와 같이 사용한다.

 

그럼 이건 구체적으로 어떻게 가능한걸까? Context Manager 에 의해 가능하다

 

ContextManager

앞서 살펴본 예시는 "리소스" 관리를 위해 필요한 것이었다. 이를 파이썬에서는 ContextManager 라는 개념으로 커버한다.

 

 

Context Manager는 리소스의 초기화와 정리를 자동으로 처리하기 위한 메커니즘이다. 주로 파일 입출력, 데이터베이스 세션 관리, 스레드 동기화 등 다양한 리소스 관리 작업에서 활용된다.

 

Context Manager는 두 가지 메서드를 구현한다:

  1. __enter__: with 블록에 진입할 때 호출되며, 필요한 리소스를 초기화하거나 준비 작업을 수행한다.
  2. __exit__: with 블록이 끝날 때 호출되며, 리소스를 정리하거나 종료한다. 예외가 발생하더라도 반드시 실행된다.

 

with 구문은 Context Manager 객체를 사용하여 작업의 시작과 종료를 자동으로 처리한다.

  1. __enter__ 메서드를 호출하고, 반환값을 as 뒤에 지정된 변수에 할당한다.
  2. with 블록의 코드를 실행한다.
  3. 블록 실행이 끝나거나 예외가 발생하면 __exit__ 메서드를 호출한다.

 

use case

SQLAlchemy 세션 관리

SQLAlchemy의 Session은 Context Manager를 구현하여 트랜잭션 관리와 세션 종료를 자동으로 처리

 

즉 이 경우에는 wth 을 transaction 단위라고 생각해도 좋다

from sqlalchemy.orm import Session
from sqlalchemy import create_engine
from my_models import MyModel

engine = create_engine("sqlite:///example.db")

with Session(engine) as session:
    session.add(MyModel(name="example"))
    session.commit()  # 데이터베이스에 반영
# 블록 종료 시 세션이 자동으로 종료된다.

 

스레드 동기화 (threading.Lock)

멀티스레드 환경에서 Lock 객체를 사용해 동기화를 처리할 때 활용하기도 함

import threading

lock = threading.Lock()

with lock:
    # 임계 구역
    print("Thread-safe code")
# 블록 종료 후 Lock이 자동으로 해제된다.

 

 

Context Manager 구현 예제

사용자 정의 Context Manager를 다음과 같이 직접 구현하는 것도 가능

 

class CustomResource:
    def __enter__(self):
        print("Resource acquired")
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        print("Resource released")
        return False  # 예외를 다시 전달

with CustomResource() as resource:
    print("Using resource")
# 블록 종료 시 `__exit__`이 호출된다.

 

Resource acquired -> Using Resource -> Using resource 순으로 출력됨

 

장점?

  1. 리소스 누수 방지: 예외가 발생하더라도 __exit__이 호출되므로 리소스 정리가 보장된다.
  2. 코드 간결성: 초기화와 정리를 수동으로 호출할 필요 없이, 간단한 구조로 관리할 수 있다.
  3. 표준화된 리소스 관리: 다양한 라이브러리와 함께 사용 가능하다.

 

기타

나는 playwright 으로 브라우저를 돌릴 때 자원관리에 실패한 적이 있었다.

왠만하면 수동으로 관리하지 말고 ContextManager 를 사용하는게 좀 더 깔끔하고 쉽긴 하다

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함