티스토리 뷰
파이썬에서 object는 "class"라 불리는 object에 의해 생성된다. 즉 다시말해 class도 object이다.
class도 object이기 때문에 object와 같은 방식으로 필드를 추가하거나 삭제하는 연산이 가능하다.
class MyClass:
pass
obj = MyClass()
MyClass.val = 3
MyClass.print = lambda self : print("Hello")
obj.print()
----------------------------------
Hello
다만 차이점은 class의 필드를 수정하면 이미 생성되 있던 instance도 포함해서 모든 instance들이 같이 수정된다.
이러한 class object를 만들어내는 또 다른 special object를 metaclass
라고 한다. 파이썬에서 디폴트 metaclass
는 type
이다. metaclass
가 어떻게 class object를 생성하는지 살펴보자.
아마 파이썬을 공부하면서 type
을 본적이 있을 것이다. type
은 인자가 하나일 때는 instance의 클래스 정보를 반환한다. 하지만 인자가 3개가 되면 새로운 class object를 만든다. 아래에서 확인해 보자.
class MyClass:
pass
MyClass = type('MyClass', (), {})
위의 두 코드는 완전히 같은 일을 한다. 위의 type은 3개의 인자를 받고있다. 첫번째 인자는 class의 이름, 두번째 인자는 상속받을 클래스리스트, 세번째는 메서드나 필드같은 namespace를 dictionary 형태로 받는다. 즉 다음의 코드는 int클래스를 상속받으면서 x라는 필드를 갖는 class object가 생성된다
MyInt = type('MyInt', (int,), {'x': 3})
y = MyInt(0)
print(y.x)
----------------------------------
3
이제 metaclass
를 정의하고 사용하는 법에 대해 더 알아보자. metaclass
는 위에서 본 type
을 상속받아서 만들 수 있다.
class MyMetaClass(type):
def __init__(cls, name, bases, namespace):
super(MyMetaClass, cls).__init__(name, bases, namespace)
cls.meta_function = lambda self: print("Hello")
class MyClass(metaclass=MyMetaClass):
pass
obj = MyClass()
obj.meta_function()
-------------------------------------
Hello
MyMetaClass를 만들어 MyClass에서 hooking하고 있다. python3에서는 위와 같이 class를 정의할 때 metaclass를 인자로 넘겨주는 방식으로 hooking한다. (python2는 다른 방식으로한다.)
metaclass
의 __new__
,__init__
, __call__
에 대해 살펴보자
class MyMetaClass(type):
def __new__(cls, *args, **kwargs):
print('__new__')
return super().__new__(cls, *args, **kwargs)
def __init__(cls, *args, **kwargs):
print('__init__')
super().__init__(*args, **kwargs)
def __call__(cls, *args, **kwargs):
print('__call__')
return super().__call__(*args, **kwargs)
class MyClass(metaclass=MyMetaClass):
pass
print("##############")
obj = MyClass()
---------------------------
__new__
__init__
##############
__call__
MyClass가 생성될때 MyMetaClass의 __new__ 가 먼저 실행되고 그 다음에 __init__이 실행되고 있다.
MyClass의 insctance를 생성할때에는 __call__이 실행된다.
metaclass
를 이용한 singleton
구현
class Singleton(type):
def __call__(cls, *args, **kwargs):
if not hasattr(cls, 'instance'):
cls.instance = super().__call__(*args, **kwargs)
return cls.instance
class MyClass(metaclass=Singleton):
pass
a = MyClass()
b = MyClass()
c = MyClass()
print(a is b)
print(b is c)
-------------------------------
True
True
'python' 카테고리의 다른 글
python3 iterator (이터레이터) (0) | 2019.01.09 |
---|