Python/파이썬 오픈소스 배포

메타 클래스 (3)

monstro 2025. 7. 5. 16:06
728x90
반응형

- 개요

파이썬에서 메타 클래스는 설계자가 정의한 방식으로 동작하므로 클래스를 유연하게 사용할 수 있다

파이썬에서 메타 클래스를 만드는 방식은 다음과 같이 구분할 수 있다

  • type 함수를 사용하여 정의하는 방식
  • type 메타 클래스상속받아 정의하는 방식

 

type 함수를 사용하여 메타 클래스를 정의하는 경우 사용방법이 간단하다는 장점이 있지만,

인스턴스의 생성 -> 초기화 -> 호출까지의 과정은 확장할 수 없다는 단점이 있다

 

반대로 type 클래스를 상속받아 메타 클래스를 정의하는 방법은 많이 복잡하지만,

__new__ , __init__, __call__ 메서드를 오버라이드하여 인스턴스에 대한 과정을 확장할 수 있다

 

 

1) type 함수를 사용한 메타 클래스 생성

def custom_multiple(self, d):
    for i in range(len(self)):
        self[i] = self[i] * d

def custom_replace(self, old, new):
    while old in self:
        self[self.index(old)] = new

CustomList1 = type(
    'CustomList1',
    (list,),
    {
        'desc' : '커스텀 리스트 1',
        'custom_multiple' : custom_multiple,
        'custom_replace' : custom_replace,
    }
)

c1 = CustomList1([1,2,3,4,5,6,7,8,9])
c1.custom_multiple(1000)
print(f"{c1}")

c1.custom_replace(1000, 7777)
print(f"{c1}")

print(f"{c1.desc}")

 

type 함수를 사용하여 기존의 List 클래스에서 기능을 확장한 메타 클래스를 만들어본다

우선 해당 클래스에서 사용할 2개의 메서드를 생성하였다

각각 리스트의 인덱스의 데이터에 값을 곱하는 함수리스트의 인덱스의 데이터를 교체하는 함수이다

 

type 함수를 사용하여 CusomList 메타 클래스를 생성한다

인자로 해당 클래스의 이름 / 부모 클래스 / 해당 클래스의 프로퍼티와 메서드를 넣어준다

 

생성한 CustomList 메타 클래스에서 인스턴스 c1을 생성하고 프로퍼티를 설정한다

이후 메서드를 호출하여 결과를 확인한다

 

 

출력된 결과는 위와 같다

우선, custom_multiple 메서드를 호출하여 1~9까지의 값에 1000이 곱해진 것을 확인할 수 있다

다음으로 custom_replace 메서드를 호출하고 1000의 값이 7777로 교체된 것을 확인할 수 있다

마지막으로 c1 인스턴스의 desc 프로퍼티에 접근하여 잘 출력된 것도 확인할 수 있다

 

2) type 클래스를 상속받아 메타 클래스 생성

type 클래스를 상속받아 메타 클래스를 만드는 경우 필요한 메서드를 내부에서 정의해야 한다

필요한 메서드의 경우 다음과 같다

  • __new__ :  클래스의 인스턴스를 생성하는 함수
  • __init__ :  인스턴스를 초기화하는 함수
  • __call__ : 인스턴스를 호출하는 함수

 

위 3가지의 함수의 호출 순서__new__ -> __init__ -> __call__ 순서로 진행된다

또한 __new__와 __call__ 함수의 경우 return을 작성하여 인스턴스를 반환해야 한다

 

...

class CustomListMeta(type):
    def __new__(metacls, name, bases, namespace):
        namespace['desc'] = '커스텀 리스트2'
        namespace['custom_multiple'] = custom_multiple
        namespace['custom_replace'] = custom_replace

        return type.__new__(metacls, name, bases, namespace)

    def __init__(self, object_or_name, bases, dict):
        super().__init__(object_or_name, bases, dict)

    def __call__(self, *args, **kwargs):
        return super().__call__(*args, **kwargs)
        
        
CustomList2 = CustomListMeta('CustomList2',(list, ),{})
c2 = CustomList2([1, 2, 3, 4, 5, 6, 7, 8, 9])

c2.custom_multiple(100)
print(f"{c2}")

c2.custom_replace(100, 777)
print(f"{c2}")

print(f"{c2.desc}")
print(f"{CustomList2.__mro__}")

 

type 클래스를 상속받은 CustomListMeta 메타 클래스를 생성하였다

내부에 __new__, __init__, __call__ 함수를 정의한다

 

__new__ 메서드에서는 metacls, name, bases, namespace의 4개의 인자를 사용하여

메타 클래스 / 클래스의 이름 / 부모 클래스 / 프로퍼티와 메서드를 정의해야 한다

마지막에 type 클래스의 __new__ 함수에 인자를 넘겨주어 인스턴스를 생성하고 반환한다

 

__init__ 메서드에서는 object_or_name, bases, dict의 3개의 인자를 사용하여

메타 클래스의 이름 / 부모 클래스 / 프로퍼티와 메서드를 정의한다

위의 구조를 완성하여 메타 클래스의 인스턴스를 완성한 구조로 초기화한다

 

__call__ 메서드에서는 부모 버전의 __call__ 메서드를 호출하고

인자를 넘겨주어 넘겨준 파라미터로 구성된 인스턴스를 호출하고 반환한다

 

최종적으로 CustomListMeta 메타 클래스를 사용하여 CustomList2 클래스를 생성하고

해당 클래스의 인스턴스 c2를 통해 메타 클래스의 동작을 확인한다

메서드와 프로퍼티에 접근한 후에, CustomList2의 부모 클래스 __mro__ 메서드로 확인한다

 

 

실행 결과는 위와 같다

인스턴스에 대한 메타 클래스의 메서드 호출이 문제없이 이뤄졌고 프로퍼티인 desc도 출려되었다

또 CustomList2의 부모 클래스인 list 클래스도 확인할 수 있다

728x90
반응형

'Python > 파이썬 오픈소스 배포' 카테고리의 다른 글

Descriptor (2)  (0) 2025.07.08
Descriptor (1)  (0) 2025.07.07
메타 클래스 (2)  (0) 2025.07.05
메타 클래스 (1)  (0) 2025.07.04
메서드 오버로딩  (0) 2025.07.02