위의 Armin Ronacher의 정확한 설명, 저의 초보자가 잘 이해할 수 있도록 답변을 확장하십시오.
정적 또는 인스턴스 메소드 (여기서 다른 유형-클래스 메소드-여기에서 논의되지 않았으므로 건너 뛰는가) 여부에 관계없이 클래스에 정의 된 메소드의 차이점은 클래스 인스턴스에 바인딩되어 있는지 여부에 있습니다. 예를 들어, 메소드가 런타임 중에 클래스 인스턴스에 대한 참조를 수신하는지 여부를 말하십시오.
class C:
a = []
def foo(self):
pass
C # this is the class object
C.a # is a list object (class property object)
C.foo # is a function object (class property object)
c = C()
c # this is the class instance
__dict__
클래스 객체 의 사전 속성은 클래스 객체의 모든 속성과 메서드에 대한 참조를 보유하므로
>>> C.__dict__['foo']
<function foo at 0x17d05b0>
foo 메소드는 위와 같이 액세스 할 수 있습니다. 여기서 주목해야 할 중요한 점은 파이썬의 모든 것이 객체이므로 위의 사전의 참조는 다른 객체를 가리키는 것입니다. 클래스 속성 객체 또는 CPO라고 부르겠습니다.
CPO가 설명자인 경우 python 인터프리터 __get__()
는 CPO 의 메소드를 호출하여 포함 된 값에 액세스합니다.
CPO가 설명자인지 확인하기 위해 Python 인터프리터는 설명자 프로토콜을 구현하는지 확인합니다. 디스크립터 프로토콜을 구현하는 것은 3 가지 방법을 구현하는 것입니다
def __get__(self, instance, owner)
def __set__(self, instance, value)
def __delete__(self, instance)
예를 들어
>>> C.__dict__['foo'].__get__(c, C)
어디
self
CPO (목록, str, 함수 등의 인스턴스 일 수 있음)이며 런타임에 의해 제공됩니다.
instance
이 CPO가 정의 된 클래스의 인스턴스 (위의 'c'개체)는 명시 적으로 제공해야합니다.
owner
이 CPO가 정의 된 클래스 (위의 클래스 개체 'C')이며 당사에서 제공해야합니다. 그러나 이것은 CPO에서 호출하기 때문입니다. 인스턴스에서 호출 할 때 런타임이 인스턴스 또는 클래스를 제공 할 수 있기 때문에 이것을 제공 할 필요가 없습니다 (다형성)
value
CPO의 의도 된 가치이며 당사가 제공해야합니다.
모든 CPO가 설명자인 것은 아닙니다. 예를 들어
>>> C.__dict__['foo'].__get__(None, C)
<function C.foo at 0x10a72f510>
>>> C.__dict__['a'].__get__(None, C)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute '__get__'
리스트 클래스가 디스크립터 프로토콜을 구현하지 않기 때문입니다.
따라서 c.foo(self)
메소드 서명이 실제로 이것이기 때문에 인수 자체 입력 이 필요합니다 C.__dict__['foo'].__get__(c, C)
(위에서 설명했듯이 C는 발견되거나 다형성 될 수 있으므로 필요하지 않습니다). 또한 필요한 인스턴스 인수를 전달하지 않으면 TypeError가 발생합니다.
메소드가 여전히 클래스 C 클래스를 통해 참조되고 클래스 인스턴스와의 바인딩은 인스턴스 오브젝트 형식의 컨텍스트를이 함수에 전달하여 수행됩니다.
컨텍스트를 유지하지 않거나 인스턴스에 바인딩하지 않기로 선택한 경우 설명자 CPO를 래핑하고 __get__()
컨텍스트가 필요하지 않도록 해당 메서드를 재정의하는 클래스를 작성하기 만하면되므로 매우 좋습니다. 이 새로운 클래스는 데코레이터라고하며 키워드를 통해 적용됩니다.@staticmethod
class C(object):
@staticmethod
def foo():
pass
새로 줄 바꿈 된 CPO에 컨텍스트가 없으면 foo
오류가 발생하지 않으며 다음과 같이 확인할 수 있습니다.
>>> C.__dict__['foo'].__get__(None, C)
<function foo at 0x17d0c30>
정적 메소드의 유스 케이스는 네임 스페이스 및 코드 유지 관리 가능성이 높습니다 (클래스에서 가져 와서 모듈 전체에서 사용할 수 있도록하는 것).
물론 액세스 인스턴스 변수, 클래스 변수 등의 메서드를 정교화해야하는 경우가 아니라면 가능할 때마다 인스턴스 메서드 대신 정적 메서드를 작성하는 것이 좋습니다. 한 가지 이유는 객체에 대한 원치 않는 참조를 유지하지 않음으로써 가비지 수집을 용이하게하는 것입니다.