정적 메소드와 클래스 메소드의 차이점


3579

함수 장식의 차이 무엇 @staticmethod하나는 장식은 @classmethod?


11
정적 메소드는 때때로 청결을 위해 파이썬의 모듈 레벨 함수로 더 좋습니다. 모듈 기능을 사용하면 필요한 기능 만 가져오고 더 이상 불필요한 "."을 방지 할 수 있습니다. 구문 (Objective-C를보고 있습니다). 클래스 메소드는 "공장 패턴"함수를 생성하기 위해 다형성과 함께 사용될 수 있으므로 더 많이 사용됩니다. 클래스 메소드가 클래스를 암시 적 매개 변수로 수신하기 때문입니다.
FistOfFury

27
tl; dr >> 정적 메소드와 클래스 메소드는 일반 메소드와 비교할 때 클래스를 사용하여 액세스 할 수 있지만 클래스 메소드와 달리 상속을 통해 정적 메소드를 변경할 수 없습니다.
imsrgadich

4
Raymond Hettinger의 관련 주제 : youtube.com/watch?v=HTLu2DFOdTg
moooeeeep

보다 정확한 youtube.com/watch?v=HTLu2DFOdTg&feature=youtu.be&t=2689 대체 생성자에는 클래스 메소드 만 필요합니다. 그렇지 않으면 (경유 / 점.) StaticMethod를 액세스하는 모든 클래스의 속성을 사용할 수 있습니다 classmethod처럼 대신 CLS의 어떻게 든 더 많은 정보를 실제 "CLASSNAME"에 의해
로버트 노박

답변:


3137

의 호출 서명에 공지 사항을 차이를 : 어쩌면 예제 코드의 약간의 도움이 될 것입니다 foo, class_foo그리고 static_foo:

class A(object):
    def foo(self, x):
        print "executing foo(%s, %s)" % (self, x)

    @classmethod
    def class_foo(cls, x):
        print "executing class_foo(%s, %s)" % (cls, x)

    @staticmethod
    def static_foo(x):
        print "executing static_foo(%s)" % x    

a = A()

다음은 객체 인스턴스가 메소드를 호출하는 일반적인 방법입니다. 객체 인스턴스 a는 암시 적으로 첫 번째 인수로 전달됩니다.

a.foo(1)
# executing foo(<__main__.A object at 0xb7dbef0c>,1)

classmethods를 사용하면 객체 인스턴스의 클래스가 암시 적으로 대신 첫 번째 인수로 전달됩니다 self.

a.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)

class_foo수업을 사용하여 전화 할 수도 있습니다 . 실제로 무언가를 클래스 메소드로 정의하면 클래스 인스턴스가 아닌 클래스에서 호출하려고하기 때문일 수 있습니다. A.foo(1)TypeError가 발생했지만 A.class_foo(1)정상적으로 작동합니다.

A.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)

사람들이 클래스 메소드를 찾은 한 가지 용도는 상속 가능한 대체 생성자 를 만드는 것 입니다.


staticmethods으로 , 둘 다 self(객체 인스턴스)도 cls(클래스)을 암시 적으로 첫 번째 인수로 전달되지 않습니다. 인스턴스 또는 클래스에서 호출 할 수 있다는 점을 제외하고는 일반 함수처럼 작동합니다.

a.static_foo(1)
# executing static_foo(1)

A.static_foo('hi')
# executing static_foo(hi)

정적 메소드는 클래스와 클래스와 논리적으로 연결된 함수를 그룹화하는 데 사용됩니다.


foo는 함수일 뿐이지 만 함수를 호출 a.foo할 때 함수 a의 첫 번째 인수로 개체 인스턴스가 바인딩 된 함수의 "부분적으로 적용되는"버전의 함수를 얻습니다 . foo인수는 2 개, 인수 a.foo는 1 개만 필요합니다.

a에 바인딩되어 foo있습니다. 이것이 아래 "바운드"라는 용어의 의미입니다.

print(a.foo)
# <bound method A.foo of <__main__.A object at 0xb7d52f0c>>

a.class_foo, a결합되지 class_foo않고 클래스가, A바인딩됩니다 class_foo.

print(a.class_foo)
# <bound method type.class_foo of <class '__main__.A'>>

정적 메소드를 사용하는 경우 여기에서는 메소드이지만 a.static_foo인수가 바인딩되지 않은 우수한 'ole 함수를 반환합니다. static_foo1 개의 인수를 a.static_foo기대하고 1 개의 인수도 기대합니다.

print(a.static_foo)
# <function static_foo at 0xb7d479cc>

물론 static_foo클래스 를 호출 할 때도 같은 일이 발생 A합니다.

print(A.static_foo)
# <function static_foo at 0xb7d479cc>

182
staticmethod를 사용하는 데 필요한 것이 무엇인지 이해하지 못합니다. 간단한 클래스 외부 함수를 사용할 수 있습니다.
Alcott

372
@Alcott : 논리적으로 클래스에 속하기 때문에 함수를 클래스로 옮길 수 있습니다. 파이썬 소스 코드 (예 : 멀티 프로세싱, 터틀, 디스 패키지)에서는 단일 밑줄 "비공개"기능을 모듈 네임 스페이스에서 "숨기기"위해 사용됩니다. 그러나 그 사용은 단지 몇 가지 모듈에 집중되어 있습니다. 아마도 그것이 주로 문체라는 것을 나타냅니다. 이 예제를 찾을 수는 없지만 @staticmethod서브 클래스로 재정 의하여 코드를 구성하는 데 도움 이 될 수 있습니다. 그것이 없으면 모듈 네임 스페이스에 떠 다니는 다양한 기능이 있습니다.
unutbu

15
... 인스턴스, 클래스 또는 정적 메소드를 사용 하는 위치이유 에 대한 설명과 함께 . 당신은 그것에 대해 한 마디도하지 않았지만 OP는 그것에 대해 물었습니다.
MestreLion

106
@Alcott : unutbu가 말했듯이 정적 메소드는 조직 / 스타일 특징입니다. 때때로 모듈에는 많은 클래스가 있으며, 어떤 도우미 함수는 주어진 클래스에 논리적으로 묶여 있고 다른 클래스에는 묶이지 않기 때문에 많은 "자유 함수"로 모듈을 "공해"하지 않는 것이 좋습니다. 정적을 사용하는 것이 좋습니다 코드에서 클래스와 함수 defs를 믹싱하는 스타일에 의존하는 것보다는 "관련"을 보여주기 위해
MestreLion

4
한 번 더 사용 @staticmethod하면 부스러기를 제거 할 수 있습니다. 파이썬으로 프로그래밍 언어를 구현하고 있습니다-라이브러리 정의 함수 execute는 사용자 정의 함수에 인스턴스 인수 (예 : 함수 본문)가 필요한 정적 메소드를 사용합니다 . 이 데코레이터는 PyCharm 인스펙터에서 "사용하지 않은 매개 변수 자체"경고를 제거합니다.
tehwalrus

798

StaticMethod를가 가에 호출 된 클래스 또는 인스턴스에 대해 아무것도 알고하는 방법입니다. 전달 된 인수를 얻습니다. 암시 적 첫 번째 인수는 없습니다. 파이썬에서는 기본적으로 쓸모가 없습니다. 정적 메소드 대신 모듈 함수를 사용할 수 있습니다.

반면에 classmethod 는 호출 된 클래스 또는 호출 된 인스턴스의 클래스를 첫 번째 인수로 전달하는 메소드입니다. 이것은 메소드가 클래스의 팩토리가되기를 원할 때 유용합니다. 메소드가 첫 번째 인수로 호출 된 실제 클래스를 가져 오므로 서브 클래스가 포함 된 경우에도 항상 올바른 클래스를 인스턴스화 할 수 있습니다. 예를 들어 dict.fromkeys()classmethod가 서브 클래스에서 호출 될 때 서브 클래스의 인스턴스를 리턴하는 방법을 관찰하십시오 .

>>> class DictSubclass(dict):
...     def __repr__(self):
...         return "DictSubclass"
... 
>>> dict.fromkeys("abc")
{'a': None, 'c': None, 'b': None}
>>> DictSubclass.fromkeys("abc")
DictSubclass
>>> 

714
정적 메서드는 쓸모가 없습니다. 논리적으로 속한 함수이기 때문에 클래스에 액세스 할 필요가 없다는 것을 나타내면서 함수를 클래스에 넣는 방법입니다.
Tony Meyer

136
따라서 '기본적으로'쓸모가 없습니다. 의존성 주입뿐만 아니라 이러한 구성은 정적 메소드의 올바른 사용이지만 Java와 같은 클래스가 아닌 모듈은 Python의 코드 구성의 기본 요소이므로 사용 및 유용성이 거의 없습니다.
토마스 Wouters

40
클래스 또는 인스턴스와 관련이없는 클래스 내부에서 메소드를 정의하는 것에 대한 논리는 무엇입니까?
벤 제임스

106
아마도 상속을 위해? 정적 메소드는 인스턴스 메소드 및 클래스 메소드와 마찬가지로 상속 및 대체 될 수 있으며 조회는 Java와 달리 예상대로 작동합니다. 정적 메소드는 클래스 또는 인스턴스에서 호출 되든 실제로 정적으로 해석되지 않으므로 클래스와 정적 메소드의 유일한 차이점은 내재 된 첫 번째 인수입니다.
haridsv

80
또한 더 깨끗한 네임 스페이스를 만들고 함수가 클래스와 관련이있는 것을 더 쉽게 이해할 수 있도록합니다.
Imbrondir

149

기본적으로 @classmethod첫 번째 인수가 (클래스 인스턴스가 아닌) 호출 된 클래스 인 메소드는 @staticmethod암시 적 인수가 없습니다.


103

공식 파이썬 문서 :

@classmethod

클래스 메서드는 인스턴스 메서드가 인스턴스를받는 것처럼 클래스를 암시 적 첫 번째 인수로받습니다. 클래스 메소드를 선언하려면 다음 관용구를 사용하십시오.

class C:
    @classmethod
    def f(cls, arg1, arg2, ...): ... 

@classmethod형태의 함수이다 장식 - 함수의 정의에 대한 설명을 참조 함수 정의 자세한.

클래스 (등 C.f()) 또는 인스턴스 (등) 에서 호출 할 수 있습니다 C().f(). 클래스를 제외하고 인스턴스는 무시됩니다. 파생 클래스에 대해 클래스 메서드가 호출되면 파생 클래스 개체가 암시 적 첫 번째 인수로 전달됩니다.

클래스 메소드는 C ++ 또는 Java 정적 메소드와 다릅니다. 원하는 staticmethod()경우이 섹션을 참조하십시오 .

static

정적 메소드는 내재 된 첫 번째 인수를받지 않습니다. 정적 메소드를 선언하려면 다음 관용구를 사용하십시오.

class C:
    @staticmethod
    def f(arg1, arg2, ...): ... 

@staticmethod형태의 함수이다 장식 - 함수의 정의에 대한 설명을 참조 함수 정의 자세한.

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

Python의 정적 메소드는 Java 또는 C ++에서 발견되는 메소드와 유사합니다. 고급 개념에 대해서는 classmethod()이 섹션을 참조하십시오 .


문서에 오류가 없습니까? staticmethod에 있지 않아야합니다. "인스턴스와 클래스는 모두 무시됩니다." 대신 "클래스를 제외하고 인스턴스가 무시됩니다."?
mirek

잘라 내기 및 붙여 넣기 오류 일 수 있지만 클래스를 무시하면 클래스에서 메서드를 호출 할 수 없습니다.
Aaron Bentley

76

다음은 이 질문에 짧은 기사입니다

@staticmethod 함수는 클래스 안에 정의 된 함수일뿐입니다. 클래스를 먼저 인스턴스화하지 않고 호출 할 수 있습니다. 상속을 통해 정의를 변경할 수 없습니다.

@classmethod 함수는 클래스를 인스턴스화하지 않고도 호출 할 수 있지만 그 정의는 상속을 통해 Parent 클래스가 아닌 Sub 클래스를 따릅니다. @classmethod 함수의 첫 번째 인수는 항상 cls (class) 여야하기 때문입니다.


1
정적 메서드를 사용하면 항상 부모 클래스에 바인딩되고 클래스 메서드를 사용하여 클래스 메서드를 선언 한 클래스 (이 경우 하위 클래스)에 바인딩됩니다.
Mohan Gulati

7
아니요. 정적 메서드를 사용하면 전혀 제한이 없습니다. 암시 적 첫 번째 매개 변수가 없습니다. classmethod를 사용하면 메소드를 호출 한 클래스 (클래스에서 직접 호출 한 경우) 또는 메소드를 호출 한 인스턴스의 클래스 (인스턴스에서 호출 한 경우)를 내재 된 첫 번째 매개 변수로 얻을 수 있습니다.
매트 앤더슨

6
클래스를 첫 번째 인수로 사용함으로써 클래스 메소드는 다른 클래스 속성 및 메소드에 직접 액세스 할 수 있지만 정적 메소드는 그렇지 않습니다 (그러면 MyClass.attr을 하드 코딩해야 함)
MestreLion

"정의는 상속을 통해 변경할 수 없습니다." 파이썬에서는 이해가되지 않습니다. 정적 메소드를 재정의 할 수 있습니다.
cz

68

@staticmethod 또는 @classmethod 사용 여부를 결정하려면 메소드 내부를 살펴 봐야합니다. 메소드가 클래스의 다른 변수 / 메소드에 액세스하는 경우 @classmethod를 사용하십시오 . 반면에, 메소드가 클래스의 다른 부분을 건드리지 않으면 @staticmethod를 사용하십시오.

class Apple:

    _counter = 0

    @staticmethod
    def about_apple():
        print('Apple is good for you.')

        # note you can still access other member of the class
        # but you have to use the class instance 
        # which is not very nice, because you have repeat yourself
        # 
        # For example:
        # @staticmethod
        #    print('Number of apples have been juiced: %s' % Apple._counter)
        #
        # @classmethod
        #    print('Number of apples have been juiced: %s' % cls._counter)
        #
        #    @classmethod is especially useful when you move your function to other class,
        #       you don't have to rename the class reference 

    @classmethod
    def make_apple_juice(cls, number_of_apples):
        print('Make juice:')
        for i in range(number_of_apples):
            cls._juice_this(i)

    @classmethod
    def _juice_this(cls, apple):
        print('Juicing %d...' % apple)
        cls._counter += 1

classmethod와 cls._counter vs. staticmethod와 Apple._counter의 장점
Robert Nowak

1
cls._countercls._counter코드가 다른 클래스에 있거나 클래스 이름이 변경된 경우에도 여전히 유효합니다 . 수업 Apple._counter에 따라 다릅니다 Apple. 다른 클래스 또는 클래스 이름이 변경되면 참조 된 클래스를 변경해야합니다.
kiamlaluno

52

파이썬에서 @staticmethod와 @classmethod의 차이점은 무엇입니까?

이 의사 코드와 같은 Python 코드를 보았을 것입니다.이 코드는 다양한 메소드 유형의 서명을 보여주고 각각을 설명하는 docstring을 제공합니다.

class Foo(object):

    def a_normal_instance_method(self, arg_1, kwarg_2=None):
        '''
        Return a value that is a function of the instance with its
        attributes, and other arguments such as arg_1 and kwarg2
        '''

    @staticmethod
    def a_static_method(arg_0):
        '''
        Return a value that is a function of arg_0. It does not know the 
        instance or class it is called from.
        '''

    @classmethod
    def a_class_method(cls, arg1):
        '''
        Return a value that is a function of the class and other arguments.
        respects subclassing, it is called with the class it is called from.
        '''

정상적인 인스턴스 방법

먼저 설명하겠습니다 a_normal_instance_method. 이를 " 인스턴스 메소드 "라고합니다. 인스턴스 메소드가 사용될 때, 부분 함수 (소스 코드에서 볼 때 모든 값에 대해 정의 된 총 함수와 반대)로 사용됩니다. 즉, 사용될 때 첫 번째 인수는 주어진 속성을 가진 객체. 개체의 인스턴스가 바인딩되어 있으며 개체의 인스턴스에서 호출되어야합니다. 일반적으로 인스턴스의 다양한 속성에 액세스합니다.

예를 들어 다음은 문자열의 인스턴스입니다.

', '

join이 문자열 에서 인스턴스 메소드를 사용하여 다른 iterable을 결합하는 경우 iterable 목록의 함수 외에도 인스턴스의 함수입니다 ['a', 'b', 'c'].

>>> ', '.join(['a', 'b', 'c'])
'a, b, c'

바운드 방법

인스턴스 메소드는 나중에 사용하기 위해 점선 조회를 통해 바인딩 될 수 있습니다.

예를 들어, str.join메소드를 ':'인스턴스에 바인딩합니다 .

>>> join_with_colons = ':'.join 

그리고 나중에 우리는 이미 첫 번째 인수가 바인딩 된 함수로 이것을 사용할 수 있습니다. 이런 식으로 인스턴스에서 부분 함수처럼 작동합니다.

>>> join_with_colons('abcde')
'a:b:c:d:e'
>>> join_with_colons(['FF', 'FF', 'FF', 'FF', 'FF', 'FF'])
'FF:FF:FF:FF:FF:FF'

정적 방법

정적 메소드는 인스턴스를 인수로 사용하지 않습니다 .

모듈 수준 기능과 매우 유사합니다.

그러나 모듈 레벨 기능은 모듈에 상주해야하며 모듈이 사용되는 다른 곳으로 특별히 가져와야합니다.

그러나 객체에 첨부 된 경우 가져 오기 및 상속을 통해 편리하게 객체를 따릅니다.

정적 메소드의 예는 str.maketrans, stringPython 3 의 모듈에서 이동 한 것 str.translate입니다. 변환 테이블을에서 사용하기에 적합합니다 . 아래에 설명 된 것처럼 문자열 인스턴스에서 사용하면 다소 어리석은 것처럼 보이지만 string모듈 에서 함수를 가져 오는 것은 다소 어색하고 클래스에서 호출 할 수있는 것이 좋습니다.str.maketrans

# demonstrate same function whether called from instance or not:
>>> ', '.maketrans('ABC', 'abc')
{65: 97, 66: 98, 67: 99}
>>> str.maketrans('ABC', 'abc')
{65: 97, 66: 98, 67: 99}

파이썬 2에서는 점점 유용성이 떨어지는 문자열 모듈에서이 함수를 가져와야합니다.

>>> import string
>>> 'ABCDEFG'.translate(string.maketrans('ABC', 'abc'))
'abcDEFG'

수업 방법

클래스 메소드는 암시 적 첫 번째 인수를 취한다는 점에서 인스턴스 메소드와 유사하지만 인스턴스를 가져 오는 대신 클래스를 사용합니다. 더 나은 의미 사용을 위해 대체 생성자로 사용되는 경우가 많으며 상속을 지원합니다.

내장 클래스 메소드의 가장 표준적인 예는 dict.fromkeys입니다. 그것은 dict의 대체 생성자로 사용됩니다 (키가 무엇인지 알고 기본값을 원할 때 적합합니다).

>>> dict.fromkeys(['a', 'b', 'c'])
{'c': None, 'b': None, 'a': None}

dict을 서브 클래스로 만들 때 동일한 생성자를 사용하여 서브 클래스의 인스턴스를 만들 수 있습니다.

>>> class MyDict(dict): 'A dict subclass, use to demo classmethods'
>>> md = MyDict.fromkeys(['a', 'b', 'c'])
>>> md
{'a': None, 'c': None, 'b': None}
>>> type(md)
<class '__main__.MyDict'>

대체 생성자의 다른 유사한 예제 는 pandas 소스 코드 를 참조하십시오 . classmethod및 공식 Python 문서도 참조하십시오 staticmethod.


43

C ++로 프로그래밍 언어를 배우기 시작한 다음 Java와 Python으로 시작했습니다. 그래서이 질문은 각각의 간단한 사용법을 이해할 때까지 나에게 많은 영향을 미쳤습니다.

클래스 메소드 : Java와 달리 Python은 C ++에 생성자 오버로드가 없습니다. 그리고 이것을 달성하기 위해 당신은 사용할 수 있습니다 classmethod. 다음 예는 이것을 설명합니다.

의 우리가 가지고 생각해 보자 Person2 개 개의 인수를 취하는 클래스 first_namelast_name와의 인스턴스를 만듭니다 Person.

class Person(object):

    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

이제 단일 이름 만 사용하여 클래스를 작성 해야하는 요구 사항이있는 경우 a 만 first_name있으면 Python에서 이와 같은 작업을 수행 할 수 없습니다 .

객체 (인스턴스)를 만들려고 할 때 오류가 발생합니다.

class Person(object):

    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

    def __init__(self, first_name):
        self.first_name = first_name

그러나 @classmethod아래 언급 한 것과 동일한 것을 달성 할 수 있습니다

class Person(object):

    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

    @classmethod
    def get_person(cls, first_name):
        return cls(first_name, "")

정적 방법 : 이것은 간단하지만 인스턴스 또는 클래스에 바인딩되지 않으며 클래스 이름을 사용하여 간단히 호출 할 수 있습니다.

위의 예에서 first_name20자를 초과하지 않는 유효성 검사가 필요하다고 가정 하면 간단히 수행 할 수 있습니다.

@staticmethod  
def validate_name(name):
    return len(name) <= 20

그리고 당신은 단순히 class name

Person.validate_name("Gaurang Shah")

2
오래된 게시물이지만 하나 또는 두 개의 인수를 허용하는 생성자를 달성하는 더 파이썬적인 방법 def __init__(self, first_name, last_name="")은 classmethod 대신 사용하는 것입니다 get_person. 이 경우에도 결과는 동일합니다.
akarilimano

31

더 좋은 질문은 "@classmethod와 @staticmethod를 언제 사용 하시겠습니까?"입니다.

@classmethod를 사용하면 클래스 정의와 연결된 개인 멤버에 쉽게 액세스 할 수 있습니다. 이것은 생성 된 객체의 인스턴스 수를 제어하는 ​​단일 클래스 또는 팩토리 클래스를 수행하는 좋은 방법입니다.

@staticmethod는 약간의 성능 향상을 제공하지만 클래스 외부에서 독립형 함수로 달성 할 수없는 클래스 내에서 정적 메소드를 생산적으로 사용하는 것을 아직 보지 못했습니다.


31

@decorators는 python 2.4에 추가되었습니다. python <2.4를 사용하는 경우 classmethod () 및 staticmethod () 함수를 사용할 수 있습니다.

예를 들어 팩토리 메소드 (어떤 인수에 따라 클래스의 다른 구현 인스턴스를 리턴하는 함수)를 작성하려는 경우 다음과 같이 할 수 있습니다.

class Cluster(object):

    def _is_cluster_for(cls, name):
        """
        see if this class is the cluster with this name
        this is a classmethod
        """ 
        return cls.__name__ == name
    _is_cluster_for = classmethod(_is_cluster_for)

    #static method
    def getCluster(name):
        """
        static factory method, should be in Cluster class
        returns a cluster object for the given name
        """
        for cls in Cluster.__subclasses__():
            if cls._is_cluster_for(name):
                return cls()
    getCluster = staticmethod(getCluster)

또한 이것은 클래스 메소드와 정적 메소드를 사용하는 좋은 예입니다. 정적 메소드는 내부적으로 클러스터 클래스를 사용하므로 클래스에 명확하게 속합니다. classmethod는 클래스에 대한 정보 만 필요하며 객체의 인스턴스는 필요하지 않습니다.

_is_cluster_for메소드를 클래스 메소드 로 만들면 얻을 수있는 또 다른 이점은 서브 클래스가 구현을 변경하기로 결정할 수 있다는 것입니다. 아마도 일반적이고 여러 유형의 클러스터를 처리 할 수 ​​있기 때문에 클래스 이름을 확인하는 것만으로는 충분하지 않습니다.


28

정적 방법 :

  • 자기 주장이없는 간단한 기능.
  • 클래스 속성에 대한 작업; 인스턴스 속성이 아닙니다.
  • 클래스와 인스턴스를 통해 호출 할 수 있습니다.
  • 내장 함수 staticmethod ()를 사용하여이를 작성합니다.

정적 메소드의 장점 :

  • 클래스 범위에서 함수 이름을 현지화합니다.
  • 함수 코드가 사용되는 위치에 더 가깝게 이동합니다.
  • 각 메소드를 특별히 가져올 필요가 없으므로 모듈 레벨 함수보다 가져 오기가 더 편리합니다.

    @staticmethod
    def some_static_method(*args, **kwds):
        pass

수업 방법 :

  • 클래스 이름으로 첫 번째 인수가있는 함수
  • 클래스와 인스턴스를 통해 호출 할 수 있습니다.
  • 이들은 클래스 메소드 내장 함수로 작성됩니다.

     @classmethod
     def some_class_method(cls, *args, **kwds):
         pass

22

@staticmethod메소드 디스크립터로서 기본 기능을 사용하지 않습니다. classmethod는 첫 번째 인수로 소유 클래스에 대한 참조를 전달하는 호출 가능한 컨테이너에 함수를 래핑합니다.

>>> class C(object):
...  pass
... 
>>> def f():
...  pass
... 
>>> staticmethod(f).__get__(None, C)
<function f at 0x5c1cf0>
>>> classmethod(f).__get__(None, C)
<bound method type.f of <class '__main__.C'>>

실제로 classmethod런타임 오버 헤드가 있지만 소유 클래스에 액세스 할 수 있습니다. 또는 메타 클래스를 사용하고 해당 메타 클래스에 클래스 메소드를 배치하는 것이 좋습니다.

>>> class CMeta(type):
...  def foo(cls):
...   print cls
... 
>>> class C(object):
...  __metaclass__ = CMeta
... 
>>> C.foo()
<class '__main__.C'>

1
나에게 즉시 발생하는 메타 클래스의 한 가지 단점은 인스턴스에서 클래스 메소드를 직접 호출 할 수 없다는 것입니다. c = C(); c.foo()AttributeError를 일으킨다 type(c).foo(). 이것은 또한 기능으로 간주 될 수 있습니다-왜 당신이 원하는지 모르겠습니다.
Aaron Hall

20

파이썬에서 정적, 클래스 또는 추상 메소드를 사용하는 방법에 대한 결정적인 안내서 는이 주제에 대한 하나의 좋은 링크이며 다음과 같이 요약합니다.

@staticmethod함수는 클래스 안에 정의 된 함수일뿐입니다. 클래스를 먼저 인스턴스화하지 않고 호출 할 수 있습니다. 상속을 통해 정의를 변경할 수 없습니다.

  • 파이썬은 객체에 대한 바운드 메서드를 인스턴스화 할 필요가 없습니다.
  • 코드의 가독성을 높이고 객체 자체의 상태에 의존하지 않습니다.

@classmethod함수는 클래스를 인스턴스화하지 않고도 호출 가능하지만 그 정의는 상속을 통해 Parent 클래스가 아닌 Sub 클래스를 따릅니다. 상속을 통해 서브 클래스가 재정의 할 수 있습니다. @classmethod함수 의 첫 번째 인수 는 항상 cls (클래스) 여야 하기 때문 입니다.

  • 예를 들어 일종의 사전 처리를 사용하여 클래스의 인스턴스를 작성하는 데 사용되는 팩토리 메소드 .
  • 정적 메소드를 호출하는 정적 메소드 : 여러 정적 메소드에서 정적 메소드를 분할하는 경우 클래스 이름을 하드 코딩하지 말고 클래스 메소드를 사용해야합니다

덕분에 @zangw - 정적 함수의 상속 불변성이 보인다 키 차이
hard_working_ant

18

첫 번째 인수 만 다릅니다 .

  • 일반적인 방법 : 현재 객체 (추가) 첫 번째 인수로 자동 전달 된 경우
  • classmethod : 현재 객체의 클래스 는 (추가) fist 인수로 자동 전달됩니다.
  • staticmethod : 추가 인수 가 자동으로 전달 되지 않습니다 . 함수에 전달한 것은 얻는 것입니다.

더 자세하게...

정상적인 방법

객체의 메소드가 호출되면 self첫 번째 인수로 추가 인수가 자동으로 부여됩니다 . 즉, 방법

def f(self, x, y)

2 개의 인수로 호출해야합니다. self자동으로 전달 되며 객체 자체 입니다.

수업 방법

방법이 장식 될 때

@classmethod
def f(cls, x, y)

자동으로 제공되는 인수는 아니다 self , 그러나 의 클래스 self .

정적 방법

방법이 장식 될 때

@staticmethod
def f(x, y)

이 방법 에는 자동 인수 가 전혀 주어 지지 않습니다 . 호출 된 매개 변수 만 제공됩니다.

사용법

  • classmethod 대체 생성자에 주로 사용됩니다.
  • staticmethod객체의 상태를 사용하지 않습니다. 클래스 외부의 함수 일 수 있습니다. 비슷한 기능을 가진 함수를 그룹화하기 위해 클래스 내부에만 배치됩니다 (예 : Java의 Math클래스 정적 메소드 와 같은 )
class Point
    def __init__(self, x, y):
        self.x = x
        self.y = y

    @classmethod
    def frompolar(cls, radius, angle):
        """The `cls` argument is the `Point` class itself"""
        return cls(radius * cos(angle), radius * sin(angle))

    @staticmethod
    def angle(x, y):
        """this could be outside the class, but we put it here 
just because we think it is logically related to the class."""
        return atan(y, x)


p1 = Point(3, 2)
p2 = Point.frompolar(3, pi/4)

angle = Point.angle(3, 2)

17

@classmethod와 @staticmethod로 장식 된 메소드의 유사점을 먼저 설명하겠습니다.

유사성 : 둘 다 클래스인스턴스 가 아니라 클래스 자체에서 호출 될 수 있습니다 . 따라서 두 가지 모두 클래스의 메소드 입니다.

차: 클래스 메서드는 클래스 자체를 첫 번째 인수로 받지만 정적 메서드는받지 않습니다.

따라서 정적 메서드는 어떤 의미에서 클래스 자체에 바인딩되지 않으며 관련 기능이있을 수 있기 때문에 거기에 매달려 있습니다.

>>> class Klaus:
        @classmethod
        def classmthd(*args):
            return args

        @staticmethod
        def staticmthd(*args):
            return args

# 1. Call classmethod without any arg
>>> Klaus.classmthd()  
(__main__.Klaus,)  # the class gets passed as the first argument

# 2. Call classmethod with 1 arg
>>> Klaus.classmthd('chumma')
(__main__.Klaus, 'chumma')

# 3. Call staticmethod without any arg
>>> Klaus.staticmthd()  
()

# 4. Call staticmethod with 1 arg
>>> Klaus.staticmthd('chumma')
('chumma',)

11

staticmethod와 classmethod에 대한 또 다른 고려 사항은 상속입니다. 다음과 같은 수업이 있다고 가정하십시오.

class Foo(object):
    @staticmethod
    def bar():
        return "In Foo"

그런 다음 bar()자식 클래스에서 재정의하려고합니다 .

class Foo2(Foo):
    @staticmethod
    def bar():
        return "In Foo2"

이것은 작동하지만 이제 bar()자식 클래스 ( Foo2) 의 구현 은 더 이상 해당 클래스에 특정한 것을 활용할 수 없습니다. 예를 들어 say 의 구현에 사용하려는 Foo2메소드가 있다고 가정 해보십시오 .magic()Foo2bar()

class Foo2(Foo):
    @staticmethod
    def bar():
        return "In Foo2"
    @staticmethod
    def magic():
        return "Something useful you'd like to use in bar, but now can't" 

여기서 해결 방법은을 호출 Foo2.magic()하는 bar()것이지만 반복하고 있습니다 ( Foo2변경 이름이있는 경우 해당 bar()방법 을 업데이트해야 함 ).

결정은 파생 클래스에서 공통 코드를 리팩토링하는 능력에 영향을 미치기 때문에 (즉, 확장에 덜 개방적이므로) 이것은 개방 / 폐쇄 원칙을 약간 위반 한 것입니다 Foo. 경우 bar()이었다 classmethod우리는 잘 될 것입니다 :

class Foo(object):
    @classmethod
    def bar(cls):
        return "In Foo"

class Foo2(Foo):
    @classmethod
    def bar(cls):
        return "In Foo2 " + cls.magic()
    @classmethod
    def magic(cls):
        return "MAGIC"

print Foo2().bar()

제공합니다 : In Foo2 MAGIC


7

예제를 사용하여 기본적인 차이점을 설명하려고합니다.

class A(object):
    x = 0

    def say_hi(self):
        pass

    @staticmethod
    def say_hi_static():
        pass

    @classmethod
    def say_hi_class(cls):
        pass

    def run_self(self):
        self.x += 1
        print self.x # outputs 1
        self.say_hi()
        self.say_hi_static()
        self.say_hi_class()

    @staticmethod
    def run_static():
        print A.x  # outputs 0
        # A.say_hi() #  wrong
        A.say_hi_static()
        A.say_hi_class()

    @classmethod
    def run_class(cls):
        print cls.x # outputs 0
        # cls.say_hi() #  wrong
        cls.say_hi_static()
        cls.say_hi_class()

1-우리는 초기화하지 않고 정적 및 클래스 메소드를 직접 호출 할 수 있습니다

# A.run_self() #  wrong
A.run_static()
A.run_class()

2- 정적 메소드는 자체 메소드를 호출 할 수 없지만 다른 정적 및 클래스 메소드를 호출 할 수 있습니다

3- 정적 메소드는 클래스에 속하며 객체를 전혀 사용하지 않습니다.

4- 클래스 메소드는 객체가 아니라 클래스에 바인딩됩니다.


광고 2 : 확실합니까? 정적 메소드는 어떻게 클래스 메소드를 호출 할 수 있습니까? (클래스에 대한) 참조가 없습니다.
mirek

7

@classmethod : 해당 클래스로 작성된 모든 인스턴스에 대한 공유 전역 액세스를 만드는 데 사용할 수 있습니다 ..... 여러 사용자가 레코드를 업데이트하는 것과 같이 .... 특히 싱글 톤을 만들 때 유용하게 사용됩니다 .. : )

@static 메소드 : 클래스 또는 인스턴스와 관련이 없습니다 ...하지만 가독성을 위해 정적 메소드를 사용할 수 있습니다


5

다음의 차이점을 고려할 수 있습니다.

Class A:
    def foo():  # no self parameter, no decorator
        pass

Class B:
    @staticmethod
    def foo():  # no self parameter
        pass

이것은 python2와 python3 사이에서 변경되었습니다.

python2 :

>>> A.foo()
TypeError
>>> A().foo()
TypeError
>>> B.foo()
>>> B().foo()

python3 :

>>> A.foo()
>>> A().foo()
TypeError
>>> B.foo()
>>> B().foo()

따라서 @staticmethodpython3에서는 클래스에서 직접 호출 된 메소드 만 사용 하는 것이 선택 사항이되었습니다. 클래스와 인스턴스에서 호출하려면 @staticmethod데코레이터 를 계속 사용해야합니다 .

다른 경우는 unutbus 답변으로 잘 다루어졌습니다.


5

클래스 메서드는 인스턴스 메서드가 인스턴스를받는 것처럼 클래스를 암시 적 첫 번째 인수로받습니다. 클래스의 객체가 아닌 클래스에 바인딩 된 메소드이며 객체 인스턴스가 아닌 클래스를 가리키는 클래스 매개 변수를 취하므로 클래스의 상태에 액세스 할 수 있습니다. 클래스의 모든 인스턴스에 적용되는 클래스 상태를 수정할 수 있습니다. 예를 들어 모든 인스턴스에 적용 할 클래스 변수를 수정할 수 있습니다.

반면에 정적 메서드는 클래스 메서드 나 인스턴스 메서드와 비교하여 암시적인 첫 번째 인수를받지 않습니다. 클래스 상태에 액세스하거나 클래스 상태를 수정할 수 없습니다. 디자인 관점에서 올바른 방법이기 때문에 클래스에만 속합니다. 그러나 기능면에서 런타임에는 클래스에 바인딩되지 않습니다.

지침으로 정적 메소드를 유틸리티로 사용하고 클래스 메소드를 예를 들어 factory로 사용하십시오. 또는 싱글 톤을 정의 할 수도 있습니다. 또한 인스턴스 메소드를 사용하여 인스턴스의 상태와 동작을 모델링하십시오.

희망이 분명했다!


4

내 기여 사이의 차이 보여 @classmethod, @staticmethod인스턴스가 간접적으로 호출 할 수 방법을 포함하고, 인스턴스 방법을 @staticmethod. 그러나 @staticmethod인스턴스에서 간접적으로 호출하는 대신 비공개로 만드는 것이 "파이썬"일 수 있습니다. 개인 메소드에서 무언가를 얻는 것은 여기에 설명되어 있지 않지만 기본적으로 동일한 개념입니다.

#!python3

from os import system
system('cls')
# %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %

class DemoClass(object):
    # instance methods need a class instance and
    # can access the instance through 'self'
    def instance_method_1(self):
        return 'called from inside the instance_method_1()'

    def instance_method_2(self):
        # an instance outside the class indirectly calls the static_method
        return self.static_method() + ' via instance_method_2()'

    # class methods don't need a class instance, they can't access the
    # instance (self) but they have access to the class itself via 'cls'
    @classmethod
    def class_method(cls):
        return 'called from inside the class_method()'

    # static methods don't have access to 'cls' or 'self', they work like
    # regular functions but belong to the class' namespace
    @staticmethod
    def static_method():
        return 'called from inside the static_method()'
# %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %

# works even if the class hasn't been instantiated
print(DemoClass.class_method() + '\n')
''' called from inside the class_method() '''

# works even if the class hasn't been instantiated
print(DemoClass.static_method() + '\n')
''' called from inside the static_method() '''
# %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %

# >>>>> all methods types can be called on a class instance <<<<<
# instantiate the class
democlassObj = DemoClass()

# call instance_method_1()
print(democlassObj.instance_method_1() + '\n')
''' called from inside the instance_method_1() '''

# # indirectly call static_method through instance_method_2(), there's really no use
# for this since a @staticmethod can be called whether the class has been
# instantiated or not
print(democlassObj.instance_method_2() + '\n')
''' called from inside the static_method() via instance_method_2() '''

# call class_method()
print(democlassObj.class_method() + '\n')
'''  called from inside the class_method() '''

# call static_method()
print(democlassObj.static_method())
''' called from inside the static_method() '''

"""
# whether the class is instantiated or not, this doesn't work
print(DemoClass.instance_method_1() + '\n')
'''
TypeError: TypeError: unbound method instancemethod() must be called with
DemoClass instance as first argument (got nothing instead)
'''
"""

2

이름에서 알 수 있듯이 클래스 메서드는 객체가 아닌 클래스를 변경하는 데 사용됩니다. 클래스를 변경하려면 클래스를 업데이트하는 방식이므로 클래스가 클래스 속성 (개체 속성이 아님)을 수정합니다. 이것이 클래스 메소드가 클래스 (일반적으로 'cls'로 표시됨)를 첫 번째 인수로 취하는 이유입니다.

class A(object):
    m=54

    @classmethod
    def class_method(cls):
        print "m is %d" % cls.m

반면에 정적 메서드는 클래스에 바인딩되지 않은 기능을 수행하는 데 사용됩니다. 즉, 클래스 변수를 읽거나 쓰지 않습니다. 따라서 정적 메서드는 클래스를 인수로 사용하지 않습니다. 클래스의 목적과 직접 관련이없는 기능을 클래스가 수행 할 수 있도록 사용됩니다.

class X(object):
    m=54 #will not be referenced

    @staticmethod
    def static_method():
        print "Referencing/calling a variable or function outside this class. E.g. Some global variable/function."

2

문자 그대로 @staticmethod 분석 다른 통찰력을 제공하는 .

클래스의 일반적인 메소드 는 인스턴스를 첫 번째 인수로 사용 하는 암시 적 동적 메소드입니다.
반대로 정적 메소드는 인스턴스를 첫 번째 인수로 사용하지 않으므로 'static' 이라고 합니다.

정적 메소드는 실제로 클래스 정의 외부의 함수와 같은 일반 함수입니다.
운이 좋게 적용되는 곳에 가까이 서기 위해 운 좋게 그룹으로 그룹화되거나 스크롤하여 찾을 수 있습니다.


2

나는 순수하게 파이썬 버전을주고 생각 staticmethod하고classmethod 언어 수준에서 그들 사이의 차이를 이해하는 데 도움이 될 것이다.

둘 다 비 데이터 디스크립터입니다 ( 먼저 디스크립터에 익숙하면 이해하기가 더 쉽습니다 ).

class StaticMethod(object):
    "Emulate PyStaticMethod_Type() in Objects/funcobject.c"

    def __init__(self, f):
        self.f = f

    def __get__(self, obj, objtype=None):
        return self.f


class ClassMethod(object):
    "Emulate PyClassMethod_Type() in Objects/funcobject.c"
    def __init__(self, f):
        self.f = f

    def __get__(self, obj, cls=None):
        def inner(*args, **kwargs):
            if cls is None:
                cls = type(obj)
            return self.f(cls, *args, **kwargs)
        return inner

1

staticmethod는 상속 계층에서 객체, 클래스 또는 부모 클래스의 속성에 액세스 할 수 없습니다. 객체를 만들지 않고 클래스에서 직접 호출 할 수 있습니다.

classmethod는 객체의 속성에 액세스 할 수 없습니다. 그러나 상속 계층 구조에서 클래스 및 상위 클래스의 속성에 액세스 할 수 있습니다. 객체를 만들지 않고 클래스에서 직접 호출 할 수 있습니다. 객체에서 호출되면 액세스하지 않고 액세스하는 일반 메소드와 동일 self.<attribute(s)>합니다self.__class__.<attribute(s)> 만.

클래스가 있다고 생각 b=2하면 객체를 만들고 객체를 다시 설정 b=4합니다. 정적 메소드는 이전의 아무것도 액세스 할 수 없습니다. Classmethod는을 .b==2통해서만 액세스 할 수 있습니다 cls.b. 일반 방법은 .b==4via self.b.b==2via 모두에 액세스 할 수 있습니다 self.__class__.b.

우리는 KISS 스타일을 따를 수있다 self.attribute(s). OOP가 그런 식으로 구현되는 언어가 있으며 이것이 나쁜 생각은 아니라고 생각합니다. :)


클래스 메소드에서 한 가지 중요한 점 : 클래스 메소드에서 속성을 수정하면이 속성을 명시 적으로 설정하지 않은이 클래스의 모든 기존 오브젝트에 수정 된 값이 있습니다.
mirek

-4

iPython의 다른 방법과 동일한 방법을 빠르게 해킹하면 @staticmethod 하면 (나노초 단위로) 약간의 성능 향상 얻을 수 있지만 그렇지 않으면 기능을 수행하지 않는 것으로 보입니다. 또한 staticmethod()컴파일하는 동안 (스크립트를 실행할 때 코드를 실행하기 전에 발생 하는) 메소드를 처리하는 추가 작업으로 인해 성능이 향상 될 수 있습니다 .

코드 가독성을 위해 @staticmethod나노초가 계산되는 많은 작업에 메소드가 사용 되지 않는 한 피 하지 않을 것 입니다.


7
"그렇지 않으면 아무런 기능도하지 않는 것 같습니다": 엄격하게 사실이 아닙니다. 위의 토론을 참조하십시오.
Keith Pinson
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.