메타 클래스 (1)
- 개요
객체지향 언어인 파이썬에서는 다른 객체지향 언어와 다르게 클래스 그 자체도 객체로 취급한다
따라서 클래스 역시 객체이므로 클래스를 생성하는 클래스 역시 존재한다
클래스를 생성하는 클래스를 메타 클래스라고 부르고 type() 함수가 대표적인 메타 클래스이다
메타 클래스를 사용하여 얻을 수 있는 가장 큰 이점은 커스텀 메타 클래스를 만들 수 있다는 점이다
커스텀 메타 클래스를 활용하여 원하는 방향으로 클래스를 생성할 수 있다
함수 오버로드나 검증 로직과 같은 확장 기능을 클래스에 부여할 수 있다
1) 인스턴스, 클래스, 메타 클래스 순서로 접근
class SampleA():
pass
obj = SampleA()
print(f"__class__ 메서드를 사용하여 인스턴스로부터 클래스 타입 판별 : {obj.__class__}")
print(f"type 함수를 사용하여 인스턴스로부터 클래스 타입 판별 : {type(obj)}")
print(f"__class__ 메서드와 type 함수 실행결과 비교 : {obj.__class__ is type(obj)}")
print(f"__class__ 메서드를 사용하여 클래스로부터 클래스 타입 판별 : {obj.__class__.__class__}")
print(f"type 함수를 사용하여 클래스로부터 클래스 타입 판별 : {type(type(obj))}")
print(f"클래스에 대한 __class__ 함수와 type 함수 실행결과 비교 : {obj.__class__.__class__ is type(type(obj))}")
print(f"__class__ 메서드를 사용하여 type 메타 클래스로부터 클래스 타입 판별 : {type.__class__}")
print(f"type 함수를 사용하여 type 메타 클래스로부터 클래스 타입 판별 : {type(type)}")
print(f"type 메타 클래스에 대한 __class__ 함수와 type 함수 실행결과 비교 : {type.__class__ is type(type)}")
위와 같은 간단한 예제를 구성해보았다
인스턴스의 클래스에 접근하기 위한 2가지 방법을 사용하였는데,
하나는 매직 메서드인 __class__를 사용하였고, 다른 하나는 type() 함수를 사용하였다
가장 먼저 SampleA 클래스의 인스턴스인 obj에 접근하였다
__class__ 메서드와 type() 함수를 실행한 결과가 모두 동일하게 SampleA 클래스로 나오는 것을 확인할 수 있다
다음으로 SampleA 클래스에 접근하였다
__class__ 메서드와 type() 함수를 실행한 결과가 모두 동일하게 type 메타 클래스로 나오는 것을 확인할 수 있다
마지막으로 type 메타 클래스에 접근하였다
확인할 수 있는 점은 type 메타 클래스의 메타 클래스가 바로 type 클래스 자기 자신이라는 점이다
2) 다른 자료형에서의 메타 클래스 확인
n = 10
d = {'a' : 10, 'b' : 20}
class SampleB():
pass
obj2 = SampleB()
for i in (n, d, obj2):
print(f"{type(i)} {type(i) is i.__class__} {i.__class__.__class__}")
이번에는 여러가지 예시로부터 type 메타 클래스를 확인해본다
n은 10의 값을 지닌 정수이고, d는 딕셔너리, obj2는 SampleB 클래스의 인스턴스이다
위 3개의 변수를 패킹하여 순회하면서
각 변수의 타입 / 각 변수의 type()과 __class__ 연산의 비교값 / __class__에 __class__ 연산을 수행한 값을 출력한다
최종 실행결과로 알 수 있는 점은 모든 클래스의 클래스는 type 메타 클래스라는 부분이다
for i in int, float, str, list, tuple, dict:
print(f"{type(i)}")
위와 같이 자료형들을 나열하고 순회하면서 type 함수를 호출하여도
결과는 동일하게 모든 클래스의 클래스는 type 클래스라는 점을 알 수 있다