메인
투자 노트

Python 메타클래스 프로토콜 이용하기

@5/31/2023

Metaclass

메타클래스가 무엇인지 모른다면 아래 글들을 읽어보자
요약
클래스와 메타클래스가 __new__ , __init__ , __call__ 메서드를 통해 객체를 구성하는 과정은 이렇다.
1.
메타클래스의 new는 클래스를 만들어서 반환한다.
2.
메타클래스의 init는 new가 만들어준 클래스를 세팅하고.
3.
메타클래스의 call은 클래스의 인스턴스를 만들어서 반환한다.
4.
클래스의 new는 메타클래스의 call을 사용해서 인스턴스를 만들어서 반환한다.
5.
클래스의 init은 클래스의 new가 만든 인스턴스를 세팅한다.
6.
클래스의 call은 클래스의 인스턴스가 호출될때의 동작을 정의한다.
예시 코드
class MyMetaClass(type): def __new__(meta, *args, **kwargs): """클래스 생성해서 반환""" print('metaclass__new__',meta, args, kwargs) # meta는 MyMetaClass 본인 ret = super().__new__(meta, *args, **kwargs) # 클래스 생성 print('metaclass__new__ ->',ret) return ret def __init__(cls, *args, **kwargs): # new와 init의 인자는 항상 두번째부터 모두 같다. """생성된 클래스를 설정할 수 있음""" print('metaclass__init__',cls, args, kwargs) # cls는 new가 생성한 클래스 ret = super().__init__(*args, **kwargs) # 반환 없음 print('metaclass__init__ ->',ret) return ret # 그냥 None임 def __call__(cls, *args, **kwargs): """ init 동작을 정의할 수 있음 """ self = super().__call__(*args, **kwargs) # 클래스의 new->init을 통해 인스턴스 생성 print('metaclass__call__',self, args, kwargs) # self는 클래스의 인스턴스 self.hello = 10 # 인스턴스에 속성 설정 가능 return self # 인스턴스 반환 class MyClass(metaclass = MyMetaClass): def __new__(self): """인스턴스 생성해서 반환""" print("class__new__") return super().__new__(self) # 메타클래스의 call을 사용해서 인스턴스 생성 def __init__(self): """생성된 인스턴스를 설정할 수 있음""" self.hello2 = 11 print('class__init__') # 클래스의 new가 생성한 인스턴스 설정 가능 def __call__(self): """인스턴스 호출 동작 정의""" print('class__call__') # 인스턴스가 호출될때 동작합 return self.hello, self.hello2 print('-------------------') obj = MyClass() obj()
Python
복사
출력
metaclass__new__ <class '__main__.MyMetaClass'> ('MyClass', (), {'__module__': '__main__', '__qualname__': 'MyClass', '__new__': <function MyClass.__new__ at 0x107e87a60>, '__init__': <function MyClass.__init__ at 0x107e87e20>, '__call__': <function MyClass.__call__ at 0x107e87ec0>, '__classcell__': <cell at 0x1078e7df0: empty>}) {} metaclass__new__ -> <class '__main__.MyClass'> metaclass__init__ <class '__main__.MyClass'> ('MyClass', (), {'__module__': '__main__', '__qualname__': 'MyClass', '__new__': <function MyClass.__new__ at 0x107e87a60>, '__init__': <function MyClass.__init__ at 0x107e87e20>, '__call__': <function MyClass.__call__ at 0x107e87ec0>, '__classcell__': <cell at 0x1078e7df0: MyMetaClass object at 0x113ec1b80>}) {} metaclass__init__ -> None ------------------- class__new__ class__init__ metaclass__call__ <__main__.MyClass object at 0x107d60650> () {} class__call__ (10, 11)
Python
복사
설명
new는 생성 init은 초기화
new가 먼저 호출되고 new가 반환한게 자신의 인스턴스가 된다. 이후 init이 호출되고 init은 그 인스턴스에 대해 설정을 할 수 있다. call은 인스턴스가 호출될때 실행된다.
클래스가 정의될 때, 메타클래스의 new에는 자기자신과 클래스 정보가 들어가서 클래스를 생성해 반환한다. 이후 init에는 new가 생성한 클래스와 클래스 정보가 들어간다 마지막으로 메타클래스의 call이 클래스의 init을 감싸며 호출된다.
메타클래스간의 상속관계는 metaclass=어쩌고 없이 그냥 상속해주면 된다.
from abc import ABCMeta class MyMetaClass(ABCMeta):
Python
복사
이렇게