클래스는 메타 클래스의 인스턴스이므로 메타 클래스의 "인스턴스 메소드"가 클래스 메소드처럼 작동하는 것은 예상치 못한 일이 아닙니다.
그러나 그렇습니다. 차이점이 있습니다. 그중 일부는 의미 이상의 것입니다.
- 가장 중요한 차이점은 메타 클래스의 메소드가 클래스 인스턴스 에서 "보이지"않는다는 것 입니다. 파이썬에서 속성 조회 (간단한 방식으로-설명자가 우선 할 수 있음)가 인스턴스에서 속성을 검색합니다-인스턴스에 속성이 없으면 Python은 해당 인스턴스의 클래스를 찾은 다음 검색을 계속합니다. 클래스의 슈퍼 클래스 이지만 클래스의 클래스에는 없습니다 . Python stdlib는
abc.ABCMeta.register
메소드 에서이 기능을 사용합니다 . 클래스 자체와 관련된 메소드는 충돌없이 인스턴스 속성으로 자유롭게 재사용 할 수 있기 때문에이 기능을 유용하게 사용할 수 있습니다 (그러나 메소드는 여전히 충돌합니다).
- 명백한 또 다른 차이점은 메타 클래스에 선언 된 메소드는 여러 클래스에서 사용할 수 있다는 것입니다. 다른 클래스 계층 구조가 있고 처리하는 것과 전혀 관련이 없지만 모든 클래스에 공통적 인 기능을 원할 경우 , 당신은 mixin 클래스를 생각해 내야합니다. 믹스 인 클래스는 두 계층 모두에 기본으로 포함되어야합니다 (예를 들어, 어플리케이션 레지스트리에 모든 클래스를 포함시키는 것). (NB. 믹스 인은 때때로 메타 클래스보다 더 나은 호출 일 수 있습니다)
- classmethod는 특수한 "classmethod"객체이고 메타 클래스의 메서드는 일반적인 함수입니다.
따라서 클래스 메소드가 사용하는 메커니즘은 " 서술자 프로토콜 "입니다. 일반 함수에는 인스턴스에서 검색 할 때 인수 __get__
를 삽입하고 self
클래스에서 검색 할 때 해당 인수를 비워 두는 메소드가 있지만, classmethod
객체에는 다른 __get__
클래스가 있으며, 클래스 자체를 "소유자" 두 상황 모두에서 첫 번째 매개 변수
이것은 대부분 실질적인 차이를 만들지 않지만, 함수에 메소드에 대한 액세스를 원한다면, 동적으로 데코레이터를 추가하거나 메타 클래스의 메소드에 대해 다른 것을 추가 meta.method
하기 위해 사용할 준비가 된 함수 cls.my_classmethod.__func__
클래스 메소드에서 검색하는 데 사용해야 classmethod
하지만 래핑을 수행하는 경우 다른 오브젝트 를 작성 하고 다시 지정해야합니다.
기본적으로 다음 두 가지 예가 있습니다.
class M1(type):
def clsmethod1(cls):
pass
class CLS1(metaclass=M1):
pass
def runtime_wrap(cls, method_name, wrapper):
mcls = type(cls)
setattr(mcls, method_name, wrapper(getatttr(mcls, method_name)))
def wrapper(classmethod):
def new_method(cls):
print("wrapper called")
return classmethod(cls)
return new_method
runtime_wrap(cls1, "clsmethod1", wrapper)
class CLS2:
@classmethod
def classmethod2(cls):
pass
def runtime_wrap2(cls, method_name, wrapper):
setattr(cls, method_name, classmethod(
wrapper(getatttr(cls, method_name).__func__)
)
)
runtime_wrap2(cls1, "clsmethod1", wrapper)
다시 말해 , 메타 클래스에 정의 된 메소드가 인스턴스에서 볼 수 있다는 점과 classmethod
객체 가 볼 수 없다는 중요한 차이점을 제외하고는 런타임에 다른 차이점이 모호하고 의미가없는 것처럼 보이지만 언어가 필요하지 않기 때문에 발생합니다. 클래스 메쏘드에 대한 특별한 규칙으로 진행 : 언어 디자인의 결과로 클래스 메쏘드를 선언하는 두 가지 방법이 가능합니다. 하나는 클래스 자체가 하나의 객체이고 다른 하나는 가능성이 있기 때문입니다. 인스턴스와 클래스에서 속성 액세스를 전문화 할 수있는 디스크립터 프로토콜 사용 :
classmethod
내장은 네이티브 코드로 정의되고 있지만, 순수한 파이썬으로 코딩 할 수 있으며, 동일한 방식으로 작동합니다. 5 라인 수준의 울부 짖는 소리는로 사용할 수 있습니다 classmethod
내장없이 런타임 차이 장식 @classmethod" at all (though distinguishable through introspection such as calls to
isinstance , and even
물론 repr`) :
class myclassmethod:
def __init__(self, func):
self.__func__ = func
def __get__(self, instance, owner):
return lambda *args, **kw: self.__func__(owner, *args, **kw)
그리고 메소드 외에 @property
메타 클래스에서 와 같은 특수 속성 은 놀라운 동작없이 전혀 동일하게 특수 클래스 속성으로 작동 한다는 점을 명심해야 합니다.