Python:Metaclass
파이썬에선 클래스도 객체이다. 클래스도 객체라면 클래스를 만드는 또 다른 클래스가 있단 말인가? 있다!! 이를 "메타 클래스"라 부른다. 클래스로 객체를 만들 듯 메타 클래스로 클래스를 만들 수 있다는 의미이다.
설명
class MyMetaclass(type):
def __new__(cls, name, bases, namespace):
# Magic happens here
return super().__new__(cls, name, bases, namespace)
class MyClass(metaclass=MyMetaclass):
pass
obj = MyClass()
파이썬의 클래스는 단순히 객체를 위한 설계도가 아닙니다. 클래스 자체도 객체입니다! 모든 객체에는 자신을 생성한 클래스가 필요합니다. 그렇다면 클래스 객체를 생성하는 것은 무엇일까요? 바로 메타클래스입니다 .
기본적으로 Python은 모든 클래스를 생성할 때 type
메타클래스를 사용합니다. 예를 들어, 다음 두 클래스는 서로 동일합니다.
# Create a MyClass object
class MyClass:
...
obj = MyClass()
# Also creates a MyClass object
obj2 = type("MyClass", (), {})
To break down what those arguments mean, here is an example that creates a class with an attribute x
and a method say_hi
, that also subclasses off object.
# type(
# name,
# bases,
# attributes
# )
CustomClass = type(
'CustomClass',
(object,),
{'x': 5, 'say_hi': lambda self: 'Hello!'}
)
obj = CustomClass()
print(obj.x) # 5
print(obj.say_hi()) # Hello!
본질적으로 메타클래스를 사용하면 클래스 생성 중에 이러한 인수를 사용자 지정하고 수정할 수 있습니다. 예를 들어, 클래스의 모든 정수 속성을 두 배로 늘리는 메타클래스는 다음과 같습니다.
class DoubleAttrMeta(type):
def __new__(cls, name, bases, namespace):
new_namespace = {}
for key, val in namespace.items():
if isinstance(val, int):
val *= 2
new_namespace[key] = val
return super().__new__(cls, name, bases, new_namespace)
class MyClass(metaclass=DoubleAttrMeta):
x = 5
y = 10
print(MyClass.x) # 10
print(MyClass.y) # 20
레지스트리에 생성된 모든 클래스를 등록하는 메타클래스의 또 다른 예는 다음과 같습니다.
# ===== Metaclass Solution =====
class RegisterMeta(type):
registry = []
def __new__(mcs, name, bases, attrs):
cls = super().__new__(mcs, name, bases, attrs)
mcs.registry.append(cls)
return cls
문제는, decorators 가 흑마법을 사용하지 않고도 이와 같은 목표를 달성할 수 있다는 것입니다 (그리고 흑마법이 종종 더 깔끔하기도 합니다).
# ===== Decorator Solution =====
def register(cls):
registry.append(cls)
return cls
@register
class MyClass:
pass
그리고 그것은 메타클래스의 가장 큰 문제점을 드러냅니다.
거의 100%의 경우, 당신은 결코 그것들을 만질 필요가 없을 것입니다.
일상적인 개발 과정에서 코드의 99%는 메타클래스가 유용한 사용 사례에 도달하지 못할 것입니다. 그리고 그 1% 중 95%는 일반 데코레이터, 던더 메서드, 또는 단순 상속만으로도 해결할 수 있습니다.
그래서 유명한 파이썬 명언이 하나 있습니다.
메타클래스는 사용자의 99%가 걱정할 필요도 없는 심오한 마법입니다. 메타클래스가 필요한지 고민한다면, 필요 없습니다. - 팀 피터스
하지만 만약 여러분이 메타클래스만이 해결할 수 있는 고유한 문제를 가진 1%에 속한다면, 메타클래스는 Python 객체 시스템의 내부를 조작할 수 있게 해주는 강력한 도구입니다.
메타클래스의 실제 사례는 다음과 같습니다:
- Python의 "ABC" 구현은 메타클래스를 사용하여 추상 클래스를 구현합니다.
- Python의 "Enum" 구현은 이를 사용하여 열거형 유형을 생성합니다.
- Django, SQLAlchemy, Pydantic, Pytest와 같은 많은 타사 라이브러리는 다양한 목적으로 메타클래스를 사용합니다.
See also
Favorite site
References
-
14_Advanced_Python_Features_-_Edward_Li's_Blog.pdf ↩