Python

python metaclass

Prower 2022. 8. 6. 05:22
728x90
반응형

python에서 클래스

  • python에서는 클래스를 객체로 취급한다.
class Foo:
    pass
  • 이렇게 클래스를 선언하는건 Foo 라는 이름의 객체가 메모리에 올라갔다는 것을 의미한다.
foo = Foo()
  • 위에서 말했던 것 처럼 python에서는 클래스도 객체이기 때문에 Foo 라는 객체가 생성됨과 동시에, Foo 클래스를 통해 foo 라는 객체를 생성했다는 의미가 된다.
  • 클래스도 객체이므로 변수 할당, 메서드 인자로 전달 등이 가능하다.
class Foo:
    pass

def print_object(v):
    print(v)

print_object(Foo)

var = Foo

print(var)

type

  • type은 2가지 기능을 갖고 있다.

자료형 확인

  • 일반적으로 우리가 아는 기능인 자료형 확인이다.
  • type의 인자로 객체를 삽입하면 해당 객체의 자료형을 반환한다.

메타클래스

  • 객체는 클래스로 부터 생성된다.
  • python에서 클래스가 객체라면 클래스(객체)를 생성하는 클래스도 있을 수 있다.
  • 메타클래스는 이처럼 객체로서의 클래스를 생성하는데 사용하는 클래스이다
  • python에서는 type이 메타클래스이다. 즉, type으로 부터 클래스를 생성할 수 있다.

예시

foo = type("Foo", (), {})

print(foo)

>
<class '__main__.Foo'>
  • type은 3개의 인자를 받아 클래스를 생성한다.
    • 생성할 클래스의 이름
    • 상속받는 클래스, tuple
    • 해당 클래스의 속성과 메서드, dictionary
  • type 사용하면 다음과 같이 클래스를 생성할 수 있다.
class Foo:
    num = 0

    def add(self, number):
        self.num += number

    def print_num(self):
        print(self.num)

type을 통한 생성

def add(self, number):
    self.num += number

def print_num(self):
    print(self.num)

Foo = type("Foo", (), {
    "num": 0,
    "add": add,
    "print_num": print_num
})

foo = Foo()
foo.add(7)
foo.print_num()

>
7

관계 정리

  • python에서는 버전에 따라 old type class, new type class가 존재한다.
  • 일반적으로 python 2버전의 클래스를 old type class로 분류한다. 해당 클래스는 type 을 상속하고 있지 않으며, 클래스로 부터 생성된 객체의 자료형은 instance 라는 type으로 표기된다.
  • python3에서 클래스는 new type class로 분류한다. type을 상속하며, 클래스로 부터 생성된 객체의 자료형은 해당 클래스를 반환한다.
class Foo:
    pass

foo = Foo()

print(type(Foo))
print(type(foo))

>
<class 'type'>
<class '__main__.Foo'>
  • 위에서 type은 메타클래스이며, 클래스는 객체로 취급된다고 했다.
  • python의 클래스는 type으로 부터 생성된 객체이며, 그 객체의 자료형은 type이다.
  • 그렇다면 type의 자료형은 어떤것일까
type(type)

>
<class 'type'>
  • type의 자료형은 type 그 자체가 된다.
  • 여기서 각 관계를 다음과 같이 정리해 볼 수 있다.
    1. foo는 Foo라는 클래스로 부터 생성된 객체이다.
    2. Foo는 type이라는 메타클래스로 부터 생성된 객체이다.
    3. type은 type이라는 메타클래스로 부터 생성된 객체이이며, 그 자체의 객체이다.

생성자 호출시 발생하는 과정

  • 일반적으로 객체 생성을 할 때 다음과 같은 방식으로 생성한다.
class Foo:
  pass

foo = Foo()
  • python에서 class를 메서드로 호출할 때 __call__ 매직 메서드가 호출된다.
  • Foo의 __call__ 메서드를 호출하면 다음과 같은 작업이 발생한다.
    1. Foo의 부모 객체의 __call__ 을 호출한다.
    2. python3 에서 클래스는 type을 상속한다고 했다. 즉, type의 __call__이 호출된다.
    3. type의 __call__ 메서드는 __new__ 와 __init__ 메서드를 호출한다.
    4. __new__ 메서드를 통해 객체가 생성되어 메모리에 올라가고 __init__ 메서드를 호출하여 객체를 초기화 한다.
  • 즉, python에서 클래스의 생성이란 type의 __call__ 을 호출하는 과정과 동일하다.
  • 다음 예시는 위 예시와 동일한 코드이다.
class Foo:
  pass

foo = type.__call__(Foo)

print(foo)

>
<__main__.Foo object at 0x100897f40>
728x90
반응형