개발/Python

[중급반] Step 6. 메타 프로그래밍과 자원 관리: Metaclass와 Context Manager

ophelisis 2025. 12. 26. 14:32
반응형

파이썬 중급 시리즈의 대미를 장식할 Step 6에서는 클래스 자체를 제어하는 **메타클래스(Metaclass)**와 안전한 자원 관리를 보장하는 **컨텍스트 매니저(Context Manager)**를 다룹니다. 이 도구들은 프레임워크나 라이브러리를 직접 설계할 때 필수적인 고수들의 테크닉입니다.


1. 🏗️ 메타클래스(Metaclass): 클래스를 만드는 클래스

파이썬에서 클래스도 하나의 '객체'입니다. 그렇다면 그 클래스 객체를 만드는 설계도는 무엇일까요? 바로 메타클래스입니다.

  • type: 파이썬의 기본 메타클래스입니다. 모든 클래스는 기본적으로 type에 의해 생성됩니다.
  • 용도: 클래스가 생성되는 시점에 속성을 자동으로 추가하거나, 클래스의 이름을 검사하는 등 클래스 정의 자체를 제어할 때 사용합니다.
Python
 
# 모든 클래스 이름을 대문자로 강제하는 메타클래스 예시
class UpperCaseMeta(type):
    def __new__(cls, name, bases, attrs):
        # name: 클래스 이름, bases: 부모 클래스, attrs: 속성 딕셔너리
        upper_attrs = {k.upper() if not k.startswith("__") else k: v for k, v in attrs.items()}
        return super().__new__(cls, name, bases, upper_attrs)

class MyClass(metaclass=UpperCaseMeta):
    say_hello = "안녕하세요"

obj = MyClass()
print(obj.SAY_HELLO) # 속성 이름이 자동으로 대문자로 변경됨

2. 🛡️ 컨텍스트 매니저(Context Manager): 안전한 자원 관리

파일을 열거나 데이터베이스를 연결할 때, 예기치 못한 에러가 발생하더라도 자원을 확실하게 반납(Close)하는 것은 매우 중요합니다. 이를 위해 with 문과 컨텍스트 매니저를 사용합니다.

  • __enter__: with 블록에 진입할 때 실행됩니다.
  • __exit__: with 블록을 빠져나갈 때 실행되며, 에러 발생 여부와 상관없이 자원을 정리합니다.
Python
 
class MyTimer:
    def __enter__(self):
        import time
        self.start = time.time()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        import time
        end = time.time()
        print(f"소요 시간: {end - self.start:.4f}s")

with MyTimer():
    # 복잡한 연산 수행
    sum(i for i in range(1000000))

3. 📝 contextlib 활용하기

클래스를 매번 정의하는 것이 번거롭다면 @contextlib.contextmanager 데코레이터와 yield를 사용하여 더 간결하게 만들 수 있습니다.

Python
 
from contextlib import contextmanager

@contextmanager
def simple_resource():
    print("--- 자원 획득 ---")
    yield "데이터"
    print("--- 자원 반납 ---")

with simple_resource() as r:
    print(f"작업 중: {r}")

4. 🔍 Type Hinting: 코드의 안정성과 가독성

중급 이상의 협업 프로젝트에서는 타입 힌팅이 필수입니다. 파이썬은 동적 언어이지만, 타입을 명시함으로써 버그를 사전에 예방할 수 있습니다.

Python
 
from typing import List, Dict, Optional

def process_users(users: List[str]) -> Optional[int]:
    if not users:
        return None
    return len(users)

💡 시니어의 조언: '단순함'이 최고의 메타 프로그래밍

메타클래스는 매우 강력하지만 남용하면 코드를 읽기 어렵게 만듭니다. "단순한 것이 복잡한 것보다 낫다"는 파이썬의 철학(Zen of Python)을 기억하세요. 명확한 이유가 없다면 일반적인 클래스 상속이나 데코레이터로 해결하는 것이 더 좋습니다.

반응형