■ 메타 클래스를 사용해 클래스 정의를 검증하는 방법을 보여준다.
• 메타 클래스를 응용하는 가장 간단한 사례는 클래스를 올바르게 정의했는지 검증하는 것이다.
• 복잡한 클래스 계층을 만들 때 스타일을 강제하거나 메소드를 오버라이드하도록 요구하거나 클래스 속성 사이에 제한을 두고 싶을 수도 있다.
• 메타 클래스는 서브 클래스가 정의될 때마다 검증 코드를 실행하는 신뢰할 만한 방법을 제공하므로 이럴 때 사용할 수 있다.
• 보통 클래스 검증 코드는 클래스의 객체가 생성될 때 __init__ 메소드에서 실행된다.
• 메타 클래스를 검증용으로 사용하면 오류를 더 빨리 일으킬 수 있다.
• 메타 클래스는 type을 상속하여 정의한다.
• 메타 클래스는 기본으로 자체의 __new__ 메소드에서 연관된 class 문의 컨텐츠를 받는다.
• 여기서 타입이 실제로 생성되기 전에 클래스 정보를 수집할 수 있다.
▶ 예제 코드 1 (PY)
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 31 32 33 |
import datetime class TestMetaClass(type): def __new__(metaClass, className, baseClassNameTuple, classMemberDictionary): print((metaClass, className, baseClassNameTuple, classMemberDictionary)) return type.__new__(meta, className, baseClassNameTuple, classMemberDictionary) class TestClass(object, metaclass = TestMetaClass): value1 = 123 def __new__(self, *args, **kwargs): print("__new__ 메소드 호출") return super().__new__(self) def __init__(self): print("__init__ 메소드 호출") def printCurrentTime(self): print(datetime.datetime.now()) testClass = TestClass() testClass.printCurrentTime() """ (<class '__main__.TestMetaClass'>, 'TestClass', (<class 'object'>,), {'__module__': '__main__', '__qualname__': 'TestClass', 'value1': 123, '__new__': <function TestClass.__new__ at 0x7ff92c9ae3b0>, '__init__': <function TestClass.__init__ at 0x7ff92c9ae4d0>, 'printCurrentTime': <function TestClass.printCurrentTime at 0x7ff92c9ae560>, '__classcell__': <cell at 0x7ff92c98bd30: empty>}) __new__ 메소드 호출 __init__ 메소드 호출 2024-06-04 16:38:58.139129 """ |
▶ 예제 코드 2 (PY)
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 31 32 33 34 |
class PolygonMetaClass(type): def __new__(metaClass, className, baseClassNameTuple, classMemberDictionary): print((metaClass, className, baseClassNameTuple, classMemberDictionary)) if baseClassNameTuple != (object,): if classMemberDictionary["sideCount"] < 3: raise ValueError("Polygons need 3+ side count") return type.__new__(metaClass, className, baseClassNameTuple, classMemberDictionary) class Polygon(object, metaclass = PolygonMetaClass): sideCount = None @classmethod def getInteriorAngle(cls): return (cls.sideCount - 2) * 100 class Triangle(Polygon): sideCount = 3 class Line(Polygon): sideCount = 1 """ (<class '__main__.PolygonMetaClass'>, 'Polygon', (<class 'object'>,), {'__module__': '__main__', '__qualname__': 'Polygon', 'sideCount': None, 'getInteriorAngle': <classmethod(<function Polygon.getInteriorAngle at 0x7f505cf02290>)>}) (<class '__main__.PolygonMetaClass'>, 'Triangle', (<class '__main__.Polygon'>,), {'__module__': '__main__', '__qualname__': 'Triangle', 'sideCount': 3}) (<class '__main__.PolygonMetaClass'>, 'Line', (<class '__main__.Polygon'>,), {'__module__': '__main__', '__qualname__': 'Line', 'sideCount': 1}) Traceback (most recent call last): File "/home/king/testproject/main.py", line 19, in <module> class Line(Polygon): File "/home/king/testproject/main.py", line 6, in __new__ raise ValueError("Polygons need 3+ side count") ValueError: Polygons need 3+ side count """ |