**메타클래스(metaclass)**와 **디스크립터(descriptor)**는 메타프로그래밍을 위한 고급 Python 기능으로 — 클래스와 속성 접근이 동작하는 방식을 제어합니다. 이들은 프레임워크(ORM, Pydantic)의 많은 "마법"을 구동하지만, 애플리케이션 코드에서 직접 작성하는 경우는 드뭅니다.
메타클래스 — "클래스를 만드는 클래스"
:
(Dog)
(Dog())
클래스가 인스턴스를 만드는 것처럼, 메타클래스는 클래스를 만듭니다. 메타클래스를 커스터마이즈하면 클래스 생성을 가로채고 수정할 수 있습니다:
class Meta(type):
def __new__(mcs, name, bases, namespace):
# 이 메타클래스를 사용하는 클래스가 정의될 때 실행됨
namespace["created_by"] = "Meta" # 그런 모든 클래스에 속성을 주입
return super().__new__(mcs, name, bases, namespace)
class MyClass(metaclass=Meta):
pass
MyClass.created_by # "Meta" — 클래스 생성 시점에 메타클래스가 주입함
이것은 프레임워크가 클래스를 자동으로 등록하거나, 정의를 검증하거나, 모든 하위 클래스에 동작을 추가하게 합니다 — 예를 들어 ORM이 클래스 속성을 데이터베이스 열로 전환하는 방법이죠.
디스크립터는 __get__/__set__/__delete__를 정의하여 속성을 읽거나 쓸 때 일어나는 일을 제어하는 객체입니다:
class Positive:
def __set_name__(self, owner, name):
self.name = f"_{name}"
def __get__(self, obj, objtype=None):
return getattr(obj, self.name)
def __set__(self, obj, value):
if value < 0:
raise ValueError("must be positive") # 할당 시 검증
setattr(obj, self.name, value)
class Account:
balance = Positive() # 클래스 속성으로서의 디스크립터
a = Account()
a.balance = 100 # Positive.__set__ 호출 → 검증
a.balance = -5 # ❌ ValueError
디스크립터는 속성 접근을 가로챕니다 — 검증, 계산된 속성, 지연 로딩을 가능하게 합니다. 사실 @property, @classmethod, @staticmethod는 모두 디스크립터로 구현됩니다.
메타클래스 → Django/SQLAlchemy ORM 모델, ABC, Pydantic, 프레임워크 등록
디스크립터 → @property, ORM 필드, 검증 라이브러리, 지연 속성
메타클래스와 디스크립터는 Python의 가장 강력한 라이브러리들 뒤에 있는 메타프로그래밍 기계입니다 — 클래스 정의를 데이터베이스 스키마로 전환하는 ORM, Pydantic 같은 검증 프레임워크, 심지어 내장 @property(디스크립터) 같은 것들이죠.
대부분의 개발자가 이들을 직접 작성하는 경우는 드물지만(그리고 더 간단한 도구로 충분할 때 이를 꺼내서는 안 됨), 이들을 이해하면 이러한 프레임워크가 클래스 수준 커스터마이즈와 제어된 속성 접근의 "마법"을 어떻게 달성하는지 명확해집니다.
이 지식은 고급 라이브러리 설계, 프레임워크 동작 디버깅, Python의 객체 모델에 대한 깊은 이해에 유용합니다 — 언어에 대한 중급과 전문가 수준의 이해를 가르는 것입니다.