다음 클래스 메소드의 차이점은 무엇입니까?
하나는 정적이고 다른 하나는 그렇지 않습니까?
class Test(object):
def method_one(self):
print "Called method_one"
def method_two():
print "Called method_two"
a_test = Test()
a_test.method_one()
a_test.method_two()
답변
파이썬에서, 구별이 바운드 및 언 바운드 방법.
기본적으로 method_one
바운드 함수 와 같은 멤버 함수에 대한 호출
a_test.method_one()
로 번역
Test.method_one(a_test)
언 바운드 메소드에 대한 호출. 이 때문에 버전에 대한 호출 method_two
이 실패합니다.TypeError
>>> a_test = Test()
>>> a_test.method_two()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: method_two() takes no arguments (1 given)
데코레이터를 사용하여 메소드의 동작을 변경할 수 있습니다
class Test(object):
def method_one(self):
print "Called method_one"
@staticmethod
def method_two():
print "Called method two"
데코레이터는 내장 된 기본 메타 클래스 type
(클래스의 클래스, 이 질문 참조 )에게에 대한 바인딩 된 메소드를 작성하지 않도록 지시합니다 method_two
.
이제 인스턴스 나 클래스에서 직접 정적 메소드를 호출 할 수 있습니다.
>>> a_test = Test()
>>> a_test.method_one()
Called method_one
>>> a_test.method_two()
Called method_two
>>> Test.method_two()
Called method_two
답변
파이썬의 메소드는 디스크립터 시스템의 기본을 이해하면 매우 간단합니다. 다음 수업을 상상해보십시오.
class C(object):
def foo(self):
pass
이제 쉘에서 해당 클래스를 살펴 보자.
>>> C.foo
<unbound method C.foo>
>>> C.__dict__['foo']
<function foo at 0x17d05b0>
foo
클래스 의 속성에 액세스하면 바인딩되지 않은 메소드를 다시 얻을 수 있지만 클래스 스토리지 (dict)에는 함수가 있습니다. 왜 그래? 그 이유는 클래스의 클래스가 __getattribute__
설명자를 해결하는를 구현하기 때문입니다. 복잡하게 들리지만 그렇지 않습니다. C.foo
이 특별한 경우 에이 코드와 대략 동일합니다.
>>> C.__dict__['foo'].__get__(None, C)
<unbound method C.foo>
함수에는 __get__
설명자를 만드는 메소드 가 있기 때문 입니다. 클래스의 인스턴스가 있다면 거의 동일 None
합니다. 클래스 인스턴스입니다.
>>> c = C()
>>> C.__dict__['foo'].__get__(c, C)
<bound method C.foo of <__main__.C object at 0x17bd4d0>>
왜 파이썬이 그렇게합니까? 메소드 객체는 함수의 첫 번째 매개 변수를 클래스의 인스턴스에 바인딩하기 때문입니다. 그곳에서 자아가 시작됩니다. 때로는 클래스가 함수를 메소드로 만드는 것을 원하지 않을 때가 있습니다 staticmethod
.
class C(object):
@staticmethod
def foo():
pass
staticmethod
장식은 클래스와 구현 더미 래핑 __get__
하는 방법으로 함수로 래핑 된 기능을 반환하지 :
>>> C.__dict__['foo'].__get__(None, C)
<function foo at 0x17d0c30>
그것을 설명하기를 바랍니다.
답변
클래스 멤버를 호출하면 Python은 자동으로 객체에 대한 참조를 첫 번째 매개 변수로 사용합니다. 변수는 self
실제로 아무것도 의미하지 않으며 단지 코딩 규칙 일뿐입니다. 원한다면 전화 할 gargaloo
수 있습니다. 즉, 통화가, 상기 method_two
인상 할 TypeError
파이썬 자동 매개 변수를 갖지 않는 것으로 정의 된 방법과 파라미터 (부모 객체에 대한 참조)를 통과하려고하기 때문에.
실제로 작동하게하려면 이것을 클래스 정의에 추가하면됩니다.
method_two = staticmethod(method_two)
또는 @staticmethod
함수 데코레이터를 사용할 수 있습니다 .
답변
>>> class Class(object):
... def __init__(self):
... self.i = 0
... def instance_method(self):
... self.i += 1
... print self.i
... c = 0
... @classmethod
... def class_method(cls):
... cls.c += 1
... print cls.c
... @staticmethod
... def static_method(s):
... s += 1
... print s
...
>>> a = Class()
>>> a.class_method()
1
>>> Class.class_method() # The class shares this value across instances
2
>>> a.instance_method()
1
>>> Class.instance_method() # The class cannot use an instance method
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unbound method instance_method() must be called with Class instance as first argument (got nothing instead)
>>> Class.instance_method(a)
2
>>> b = 0
>>> a.static_method(b)
1
>>> a.static_method(a.c) # Static method does not have direct access to
>>> # class or instance properties.
3
>>> Class.c # a.c above was passed by value and not by reference.
2
>>> a.c
2
>>> a.c = 5 # The connection between the instance
>>> Class.c # and its class is weak as seen here.
2
>>> Class.class_method()
3
>>> a.c
5
답변
멤버 함수를 정의하고 있지만 함수의 멤버를 알려주지 않기 때문에 method_two는 작동하지 않습니다. 마지막 줄을 실행하면 다음을 얻을 수 있습니다.
>>> a_test.method_two()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: method_two() takes no arguments (1 given)
클래스의 멤버 함수를 정의하는 경우 첫 번째 인수는 항상 ‘self’여야합니다.
답변
위의 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>
정적 메소드의 유스 케이스는 네임 스페이스 및 코드 유지 관리 가능성이 높습니다 (클래스에서 가져 와서 모듈 전체에서 사용할 수 있도록하는 것).
물론 액세스 인스턴스 변수, 클래스 변수 등의 메서드를 정교화해야하는 경우가 아니라면 가능할 때마다 인스턴스 메서드 대신 정적 메서드를 작성하는 것이 좋습니다. 한 가지 이유는 객체에 대한 원치 않는 참조를 유지하지 않음으로써 가비지 수집을 용이하게하는 것입니다.
답변
그것은 오류입니다.
우선, 첫 번째 줄은 다음과 같아야합니다 (자본에주의하십시오)
class Test(object):
클래스의 메소드를 호출 할 때마다 첫 번째 인수 (따라서 이름 self)로 메소드를 가져오고 method_two는이 오류를 발생시킵니다
>>> a.method_two()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: method_two() takes no arguments (1 given)