[python] 클래스 본문 내에서 클래스 staticmethod를 호출합니까?

클래스 본문 내에서 정적 메소드를 사용하려고 할 때 내장 staticmethod함수를 장식 자로 사용하여 정적 메소드를 다음과 같이 정의하십시오 .

class Klass(object):

    @staticmethod  # use as decorator
    def _stat_func():
        return 42

    _ANS = _stat_func()  # call the staticmethod

    def method(self):
        ret = Klass._stat_func() + Klass._ANS
        return ret

다음과 같은 오류가 발생합니다.

Traceback (most recent call last):<br>
  File "call_staticmethod.py", line 1, in <module>
    class Klass(object):
  File "call_staticmethod.py", line 7, in Klass
    _ANS = _stat_func()
  TypeError: 'staticmethod' object is not callable

왜 이런 일이 발생하는지 이해하고 (descriptor binding)_stat_func() 마지막 사용 후 정적 메소드 로 수동으로 변환 하여 해결할 수 있습니다 .

class Klass(object):

    def _stat_func():
        return 42

    _ANS = _stat_func()  # use the non-staticmethod version

    _stat_func = staticmethod(_stat_func)  # convert function to a static method

    def method(self):
        ret = Klass._stat_func() + Klass._ANS
        return ret

그래서 내 질문은 :

더 깨끗하거나 더 많은 “Pythonic”에서와 같이 더 나은 방법이 있습니까?



답변

staticmethod객체 __func__에는 원래 원시 함수를 저장 하는 속성 이있는 것 같습니다 (그렇게해야한다는 의미가 있습니다). 그래서 이것은 작동합니다 :

class Klass(object):

    @staticmethod  # use as decorator
    def stat_func():
        return 42

    _ANS = stat_func.__func__()  # call the staticmethod

    def method(self):
        ret = Klass.stat_func()
        return ret

옆으로 정적 메서드 객체에 원래 함수를 저장하는 일종의 속성이 있다고 생각했지만 구체적인 내용은 알지 못했습니다. 누군가에게 물고기를주는 대신 물고기를 가르치는 정신으로, 이것이 내가 조사하고 찾은 것입니다 (파이썬 세션의 C & P).

>>> class Foo(object):
...     @staticmethod
...     def foo():
...         return 3
...     global z
...     z = foo

>>> z
<staticmethod object at 0x0000000002E40558>
>>> Foo.foo
<function foo at 0x0000000002E3CBA8>
>>> dir(z)
['__class__', '__delattr__', '__doc__', '__format__', '__func__', '__get__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
>>> z.__func__
<function foo at 0x0000000002E3CBA8>

대화식 세션에서 비슷한 종류의 파기 ( dir매우 도움이 됨)는 종종 이러한 종류의 질문을 매우 빠르게 해결할 수 있습니다.


답변

이것이 내가 선호하는 방식입니다.

class Klass(object):

    @staticmethod
    def stat_func():
        return 42

    _ANS = stat_func.__func__()

    def method(self):
        return self.__class__.stat_func() + self.__class__._ANS

DRY 원칙Klass.stat_func 때문에이 솔루션을 선호합니다 . Python 3에 새로운 기능이있는 이유 를 상기시킵니다. 🙂super()

그러나 나는 다른 것에 동의합니다. 일반적으로 가장 좋은 선택은 모듈 수준 기능을 정의하는 것입니다.

예를 들어 @staticmethod함수를 사용하면 재귀가 잘 보이지 않을 수 있습니다 ( Klass.stat_funcinside 를 호출하여 DRY 원리를 깨야합니다 Klass.stat_func). self내부 정적 메서드에 대한 참조가 없기 때문 입니다. 모듈 레벨 기능을 사용하면 모든 것이 정상으로 보입니다.


답변

클래스 정의 후에 클래스 속성을 주입하는 것은 어떻습니까?

class Klass(object):

    @staticmethod  # use as decorator
    def stat_func():
        return 42

    def method(self):
        ret = Klass.stat_func()
        return ret

Klass._ANS = Klass.stat_func()  # inject the class attribute with static method value


답변

이것은 staticmethod가 디스크립터이기 때문에 디스크립터 프로토콜을 실행하고 실제 호출 가능을 얻으려면 클래스 레벨 속성 페치가 필요합니다.

소스 코드에서 :

클래스 (예 🙂 C.f()또는 인스턴스 (예 :)에서 호출 할 수 있습니다 C().f(). 클래스를 제외하고 인스턴스는 무시됩니다.

그러나 클래스가 정의되는 동안 클래스 내부에서 직접하지는 않습니다.

그러나 한 논평자가 언급했듯이 이것은 실제로 “Pythonic”디자인이 아닙니다. 대신 모듈 레벨 기능을 사용하십시오.


답변

이 솔루션은 어떻습니까? @staticmethod데코레이터 구현 에 대한 지식에 의존하지 않습니다 . 내부 클래스 StaticMethod는 정적 초기화 함수의 컨테이너로 재생됩니다.

class Klass(object):

    class StaticMethod:
        @staticmethod  # use as decorator
        def _stat_func():
            return 42

    _ANS = StaticMethod._stat_func()  # call the staticmethod

    def method(self):
        ret = self.StaticMethod._stat_func() + Klass._ANS
        return ret


답변