사용자 정의 메타클래스 작성
메타클래스에서 __new__와 __init__을 사용해 클래스 생성을 사용자 지정합니다.
사용자 정의 메타클래스 작성은(는) CoddyKit의 무료 Python Academy 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Python Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Python Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
메타클래스 선언
사용자 지정 메타클래스를 사용하려면 클래스 정의에 metaclass=MyMeta를 전달하세요. 메타클래스는 type을 상속해야 합니다.
class MyMeta(type):
pass
class Foo(metaclass=MyMeta):
pass
print(type(Foo)) # <class '__main__.MyMeta'>__new__ 재정의
__new__(mcs, name, bases, namespace)은 클래스 객체를 만듭니다. 클래스가 생성되기 전에 네임스페이스를 수정할 때 사용하세요.
class UpperAttrMeta(type):
def __new__(mcs, name, bases, namespace):
upper = {k.upper(): v for k, v in namespace.items()
if not k.startswith("_")}
return super().__new__(mcs, name, bases, {**namespace, **upper})
class Config(metaclass=UpperAttrMeta):
debug = True
print(Config.DEBUG) # True__init__ 재정의
__init__(cls, name, bases, namespace)은 클래스가 생성된 후에 실행됩니다. 등록과 같은 생성 후 설정에 사용하세요.
_registry = {}
class AutoRegisterMeta(type):
def __init__(cls, name, bases, namespace):
super().__init__(name, bases, namespace)
if bases: # skip the base class itself
_registry[name] = cls
class Handler(metaclass=AutoRegisterMeta): pass
class JSONHandler(Handler): pass
class XMLHandler(Handler): pass
print(_registry) # {'JSONHandler': ..., 'XMLHandler': ...}인터페이스 계약 적용
필수 메서드가 클래스 본문에 없으면 __new__에서 TypeError를 발생시키세요.
class InterfaceMeta(type):
REQUIRED = frozenset({"process", "validate"})
def __new__(mcs, name, bases, ns):
if bases and not mcs.REQUIRED.issubset(ns):
missing = mcs.REQUIRED - ns.keys()
raise TypeError(f"{name} must define: {missing}")
return super().__new__(mcs, name, bases, ns)
class Worker(metaclass=InterfaceMeta):
def process(self): ...
def validate(self): ...메타클래스를 통한 Singleton
메타클래스의 __call__을 재정의해 인스턴스 생성을 가로채고 매번 같은 인스턴스를 반환하세요.
class SingletonMeta(type):
_instances = {}
def __call__(cls, *a, **kw):
if cls not in cls._instances:
cls._instances[cls] = super().__call__(*a, **kw)
return cls._instances[cls]
class DB(metaclass=SingletonMeta):
pass
print(DB() is DB()) # True메서드 동적 추가
메타클래스를 사용하는 모든 클래스에 유틸리티 메서드를 주입하면 각 클래스를 개별적으로 수정하지 않아도 됩니다.
class MethodInjectorMeta(type):
def __new__(mcs, name, bases, ns):
ns["describe"] = lambda self: f"I am {type(self).__name__}"
return super().__new__(mcs, name, bases, ns)
class Widget(metaclass=MethodInjectorMeta):
pass
print(Widget().describe()) # I am Widget정렬된 네임스페이스를 위한 __prepare__
__prepare__를 재정의해 사용자 지정 매핑을 클래스 네임스페이스로 제공하세요. 예를 들어 정의 순서를 보존하거나 중복을 감지할 때 사용할 수 있습니다.
class NoDuplicatesMeta(type):
class _NS(dict):
def __setitem__(self, k, v):
if k in self and not k.startswith("_"):
raise ValueError(f"Duplicate attribute: {k}")
super().__setitem__(k, v)
@classmethod
def __prepare__(mcs, name, bases):
return mcs._NS()메타클래스 충돌 해결
기반 클래스가 여러 개이고 서로 다른 메타클래스를 사용하면 Python은 가장 파생된 메타클래스를 명시적으로 사용하도록 요구합니다. 그렇지 않으면 충돌 오류가 발생합니다.
class MetaA(type): pass
class MetaB(type): pass
# class Bad(A, B): pass # TypeError: metaclass conflict
class MetaAB(MetaA, MetaB): pass # resolve manually
class A(metaclass=MetaA): pass
class B(metaclass=MetaB): pass
class Good(A, B, metaclass=MetaAB): pass메타클래스와 __init_subclass__ 비교
서브클래스 등록과 간단한 훅에는 __init_subclass__가 더 간단하며 메타클래스가 필요하지 않습니다.
class Base:
_registry = []
def __init_subclass__(cls, **kw):
super().__init_subclass__(**kw)
Base._registry.append(cls)
class ChildA(Base): pass
class ChildB(Base): pass
print(Base._registry) # [ChildA, ChildB]속성 접근 추적
메타클래스에서 __getattribute__를 재정의하면 클래스의 속성 접근을 가로챌 수 있습니다(인스턴스의 속성 접근이 아닙니다).
class TraceMeta(type):
def __getattribute__(cls, name):
val = super().__getattribute__(name)
if not name.startswith("_"):
print(f"Accessing class attr: {name}")
return val
class Config(metaclass=TraceMeta):
HOST = "localhost"
_ = Config.HOST # logs: Accessing class attr: HOSTORM 필드 수집 패턴
Django 스타일 ORM은 메타클래스를 사용해 클래스 본문의 Field 디스크립터를 _meta 레지스트리로 수집합니다.
class Field:
def __init__(self, col): self.col = col
class ModelMeta(type):
def __new__(mcs, name, bases, ns):
fields = {k: v for k, v in ns.items() if isinstance(v, Field)}
ns["_fields"] = fields
return super().__new__(mcs, name, bases, ns)
class User(metaclass=ModelMeta):
name = Field("name")
email = Field("email")
print(User._fields.keys()) # dict_keys(['name', 'email'])빠른 확인
사용자 지정 메타클래스에서 클래스 객체 자체를 생성하는 메서드는 무엇입니까(__init__ 전에 호출됨)?
복습
사용자 지정 메타클래스는 __new__/__init__을 재정의해 클래스 생성을 제어합니다. 계약 적용, 서브클래스 자동 등록, 메서드 주입 또는 필드 디스크립터 수집에 사용할 수 있습니다. 간단한 등록이 필요할 때는 __init_subclass__를 우선 사용하세요.
자주 묻는 질문
“사용자 정의 메타클래스 작성” 강의는 무료인가요?
네 — “사용자 정의 메타클래스 작성” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Python Academy 강의 전체를 잠금 해제할 수 있습니다. Python Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“사용자 정의 메타클래스 작성”에서 뭘 배우나요?
메타클래스에서 __new__와 __init__을 사용해 클래스 생성을 사용자 지정합니다. 브라우저에서 직접 실행하는 실습 코드로 Python Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Python Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Python Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.
“사용자 정의 메타클래스 작성” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Python Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Python Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.