우리가 pyhton에서 늘상 사용하는 instance(인스턴스)와 object(객체)에 대해 이야기해보자.
우리가 객체 지향 언어를 배울 떄, 일반적으로 클래스 즉, 붕어빵 틀에서 실체인 붕어빵이 생성된다고 배우곤 한다.
보통 그 붕어빵을 객체 또는 인스턴스라고 한다. 그렇다면 그 둘의 차이는 무엇일까?
위 예시를 보면, exampleA 클래스가 정의되었고, 이를 obj1이라는 변수(객체)에 할당한 것을 알 수 있다.
이는 obj1은 객체이고, 클래스(examplA)를 변수(obj1)에 인스턴스화 했다는 것을 의미한다.
즉, 인스턴스라는 말은 특정 객체가 어떤 클래스의 객체인지를 관계 위주로 설명할 때 사용한다.
여기서 변수 obj1, 즉 객체는 다른 변수에 할당할 수도, 복사할 수도, 새로운 속성을 추거하거나 함수의 인자로 넘길 수도 있다.
이는 클래스도 마찬가지다. 즉 pyhton에선 클래스도 객체이다.
아까의 예시에서, 객체 obj1의 클래스 이름을 가져오면, exampleA가 출력이 된다.
그렇다면 클래스도 객체이기 떄문에, exampleA의 클래스는 무엇인지 확인해보자.
이때, <class 'type'> 가 출력되는 것을 확인할 수 있다.
즉 우리가 보편적으로 사용하는 클래스도 다른 무언가에 의해 만들어졌다는 것이고 이게 우리가 공부할 meta class(메타 클래스) 이다.
메타 클래스는 클래스의 클래스라고 생각하면 이해하기 쉽다.
일반적으로 우리가 특별하게 구현하지 않는다면, 메타클래스는 디폴트 값으로 정해져있다.
(실제적으로 프레임워크 구현 때 아니면 잘 다루지 않을 수도?)
그런데 우리가 특정 클래스를 만들고, 특별 규칙을 만들고 싶을 때, 즉 재정의하여 클래스의 동작을 내 뜻대로 커스텀 하고 싶을 때 메타 클래스를 쓴다.
그렇다면 메타 클래스는 어떻게 사용할까?
두 가지 방법이 있다.
첫 번째는 type을 사용하여 동적으로 클래스를 생성하는 방식이다.
일반적으로 우리가 type은 자료형 종류를 알아내기 위해 type(a) 방식으로 자주 사용한다.
이와 다르게, 메타 클래스와 관련하여 사용하려면 type의 변수로 ( 클래스 이름, 상속받는 부모 클래스(tuple), 속성/메소드(dict) ) 를 받는다.
type( '클래스이름', (상속받을 부모 클래스), {속성/ 메소드} )
ex)
type('example1', ( ), { }) --- (1)
class example1( ): --- (2)
pass
(1) 과 (2) 는 같은 내용
메타 클래스를 만드는 두 번째 방법은 type을 상속받아 구현하는 방식이다.
아래 화면에 나온 것처럼, 클래스 생성 단계에서 type을 상속받게끔 설정한 후, __new__메소드를 활용하여 메타 클래스를 구현한다.
new 메소드는 4개의 인자를 받는데, 여기서 기억해야하는 것은 마지막 namespace이다.
이 부분은 메타 클래스로 클래스를 만들 떄, 속성과 메소드 부분으로 사용될 것을 명시하는 곳이다.
즉, tyep을 직접 사용하여 클래스를 만들 때, 가장 마지막 dict 부분이다.
아래는 type을 상속받아 구현한 예시 화면이다.
먼저 cus_mul, cus_replace에 대한 정의를 먼저 한 후, 메타 클래스 설정 시, 이를 __new__ 메소드의 namespace에 할당했다.
메소드 실행 순서는 'new > init > call' 이며, 메타 클래스는 메타 클래스를 상속한 클래스가 생성될 떄 call이 호출된다.
이는 메타 클래스의 생성은 메타 클래스를 상속한 클래스가 생성될 때 이루어지는 것이 아니기 떄문이다.
new는 클래스 인스턴스 생성(메모리 할당), init은 생성된 인스턴스 초기화, call은 인스턴스 실행의 역할을 한다.
위 예시를 통해 실제 할당 후 검증 화면이다.
L로 초기화를 할 때, pracList의 변수로 리스트를 선언하는 이유는
처음 인스턴스(cus_mul과 cus_replace) 생성 때 만들어놓은 self 가 클래스 생성 시에 사용되기 때문에
self 에 해당하는 리스트를 설정하는 것이다.
'Studying > Python' 카테고리의 다른 글
9. logging(로깅) - (1) (0) | 2022.03.04 |
---|---|
8. descriptor(디스크립터) (0) | 2022.03.03 |
6. method overriding, method overloading(메소드 오버라이딩, 메소드 오버로딩) (0) | 2022.03.01 |
5. getter, setter, property (0) | 2022.02.27 |
4. 접근 지정자(Access Modifier) (0) | 2022.02.27 |