# 같은 형태의 클래스를 여러개 사용할때 효과적으로 생성
class AttributeInitType(type):
def __call__(self, *args, **kwargs):
obj = type.__call__(self, *args)
for name, value in kwargs.items():
setattr(obj, name, value)
return obj
class Submarine(object, metaclass = AttributeInitType):
# attrs = ['color', 'year', 'name']
pass
sub = Submarine(name = 'Narwal', year = 2000, color = 'Black')
print(sub.year)
# 결과
2000
# 상속으로는 부모 클래스의 __init__이 실행되지 않는다.
class Meta():
def __init__(self, name, bases, namespace):
self.val = 10
class Ma(Meta):
pass
print(Ma.val)
# 결과
AttributeError: type object 'Ma' has no attribute 'val'
# metaclass로는 __init__이 실행된다.
class Meta(type):
def __init__(self, *args):
self.val = 10
class Ma(metaclass=Meta):
pass
print(Ma.val)
print(Ma().val)
# 결과
10
10
# 상속과는 달리 metaclass를 이용해 만들어진 객체 참조로는 자기 자신의 메쏘드만 접근 가능하다.
class Meta(type):
def go(self):
return "go"
class Ma(metaclass=Meta):
def ma(self):
return "Ma"
m1 = Ma()
print(m1.ma())
# 결과
Ma
m1 = Ma()
print(m1.go())
# 결과
AttributeError: 'Ma' object has no attribute 'go'
"""
metaclass를 사용하는 목적이 동적으로 객체 생성을 하기 위함이므로
metaclass 자체는 __init__을 실행할 필요가 없다.
따라서, 초기화가 아닌 객체 생성만 목적으로 하면 __new__만 사용한다.
"""
class Meta(type):
def __new__(self, *a):
self.val = 10 # do something
return type.__new__(self, *a)
class Ma(metaclass=Meta):
pass
m1 = Ma # 인스턴스를 만들 수 없고 메타 클래스의 인스턴스만 가르킨다.
print(m1.val)
# 결과
10
m1.val = 20 # 생성된 객체를 리턴하기 때문에 인자 전달도 가능하다.
print(m1.val)
# 결과
20
댓글 영역