장식 기능의 차이 무엇입니까 @staticmethod
및 장식 한 @classmethod
?
질문자 :Daryl Spitzer
약간의 예제 코드가 도움이 될 것입니다. foo
, class_foo
및 static_foo
호출 서명의 차이점을 확인하십시오.
class A(object): def foo(self, x): print(f"executing foo({self}, {x})") @classmethod def class_foo(cls, x): print(f"executing class_foo({cls}, {x})") @staticmethod def static_foo(x): print(f"executing static_foo({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
를 호출할 수도 있습니다. 사실, 당신이 어떤 것을 classmethod로 정의한다면, 그것은 아마도 당신이 그것을 클래스 인스턴스가 아니라 클래스에서 호출하려고 하기 때문일 것입니다. 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'>>
여기에서 staticmethod를 사용하면 a.static_foo
가 메서드임에도 불구하고 바인딩된 인수가 없는 좋은 ole 함수를 반환합니다. static_foo
는 1개의 인수를 예상하고 a.static_foo
는 1개의 인수도 예상합니다.
print(a.static_foo) # <function static_foo at 0xb7d479cc>
물론 대신 클래스 A
static_foo
를 호출할 때도 같은 일이 발생합니다.
print(A.static_foo) # <function static_foo at 0xb7d479cc>
unutbu
정적 메서드는 호출된 클래스나 인스턴스에 대해 아무것도 모르는 메서드입니다. 암시적인 첫 번째 인수가 아닌 전달된 인수만 가져옵니다. Python에서는 기본적으로 쓸모가 없습니다. 정적 메서드 대신 모듈 함수를 사용할 수 있습니다.
반면에 classmethod 는 호출된 클래스 또는 호출된 인스턴스의 클래스를 첫 번째 인수로 전달하는 메서드입니다. 이것은 메서드가 클래스의 팩토리가 되기를 원할 때 유용합니다. 첫 번째 인수로 호출된 실제 클래스를 가져오기 때문에 하위 클래스가 포함된 경우에도 항상 올바른 클래스를 인스턴스화할 수 있습니다. dict.fromkeys()
가 서브클래스에서 호출될 때 서브클래스의 인스턴스를 반환하는 방법을 관찰하십시오.
>>> class DictSubclass(dict): ... def __repr__(self): ... return "DictSubclass" ... >>> dict.fromkeys("abc") {'a': None, 'c': None, 'b': None} >>> DictSubclass.fromkeys("abc") DictSubclass >>>
Thomas Wouters
기본적으로 @classmethod
는 첫 번째 인수가 클래스 인스턴스가 아닌 호출된 클래스인 메서드를 만들고 @staticmethod
에는 암시적 인수가 없습니다.
Terence Simpson
공식 파이썬 문서:
클래스 메소드는 인스턴스 메소드가 인스턴스를 수신하는 것처럼 클래스를 암시적 첫 번째 인수로 수신합니다. 클래스 메서드를 선언하려면 다음 관용구를 사용하세요.
class C: @classmethod def f(cls, arg1, arg2, ...): ...
@classmethod
형태의 함수이다 장식 - 함수의 정의에 대한 설명을 참조 함수 정의 자세한.
Cf()
) 또는 인스턴스(예:C().f()
)에서 호출할 수 있습니다. 해당 클래스를 제외하고 인스턴스는 무시됩니다. 파생 클래스에 대해 클래스 메서드가 호출되면 파생 클래스 개체가 암시된 첫 번째 인수로 전달됩니다.클래스 메소드는 C++ 또는 Java 정적 메소드와 다릅니다. 원하는 경우 이 섹션의
staticmethod()
정적 메서드는 암시적 첫 번째 인수를 받지 않습니다. 정적 메서드를 선언하려면 다음 관용구를 사용합니다.
class C: @staticmethod def f(arg1, arg2, ...): ...
@staticmethod
형태의 함수이다 장식 - 함수의 정의에 대한 설명을 참조 함수 정의 자세한.
Cf()
) 또는 인스턴스(예:C().f()
)에서 호출할 수 있습니다. 해당 클래스를 제외하고 인스턴스는 무시됩니다.Python의 정적 메소드는 Java 또는 C++에서 볼 수 있는 것과 유사합니다. 고급 개념은 이 섹션의
classmethod()
Chris B.
다음 은 이 질문에 대한 짧은 기사입니다.
@staticmethod 함수는 클래스 내부에 정의된 함수일 뿐입니다. 클래스를 먼저 인스턴스화하지 않고 호출할 수 있습니다. 정의는 상속을 통해 변경할 수 없습니다.
@classmethod 함수도 클래스를 인스턴스화하지 않고 호출할 수 있지만 그 정의는 상속을 통해 Parent 클래스가 아닌 Sub 클래스를 따릅니다. @classmethod 함수의 첫 번째 인수는 항상 cls(클래스)여야 하기 때문입니다.
Tom Neyland
사용 여부를 결정 @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
Du D.
Python에서 @staticmethod와 @classmethod의 차이점은 무엇입니까?
다양한 메서드 유형의 서명을 보여주고 각각을 설명하는 독스트링을 제공하는 이 의사 코드와 같은 Python 코드를 본 적이 있을 것입니다.
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
다른 반복 가능한 가입이 문자열에, 그것은 매우 분명하게 반복 가능한 목록의 함수 일뿐만 아니라, 인스턴스의 함수이다 ['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'
정적 메서드
정적 메서드는 인스턴스를 인수로 사용하지 않습니다.
모듈 수준 기능과 매우 유사합니다.
그러나 모듈 수준 함수는 모듈에 있어야 하며 특별히 사용되는 다른 위치로 가져와야 합니다.
하지만 객체에 붙이면 import와 상속을 통해서도 객체를 편리하게 따라가게 됩니다.
고정 방법의 일례이다 str.maketrans
로부터 이동 string
그것은 의한 소비를위한 변환 테이블에 적합하다 파이썬 3에서 모듈 str.translate
. 아래에 설명된 것처럼 문자열의 인스턴스에서 사용할 때 다소 어리석은 것처럼 보이지만 string
모듈에서 함수를 가져오는 것은 다소 서툴고 str.maketrans에서와 같이 클래스에서 호출할 수 있는 것이 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.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
및 staticmethod
에 대한 공식 Python 문서도 참조하십시오.
Aaron Hall
저는 C++, Java, Python으로 프로그래밍 언어를 배우기 시작했습니다. 그래서 각각의 간단한 사용법을 이해할 때까지 이 질문도 저를 많이 괴롭혔습니다.
클래스 방법: Python은 Java 및 C++와 달리 생성자 오버로딩이 없습니다. 그래서 이것을 달성하기 위해 classmethod
사용할 수 있습니다. 다음 예는 이것을 설명합니다
first_name
과 last_name
두 개의 인수를 Person
인스턴스를 생성 Person
클래스가 있다고 가정해 봅시다.
class Person(object): def __init__(self, first_name, last_name): self.first_name = first_name self.last_name = last_name
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_name
이 20자를 초과해서는 안 된다는 유효성 검사가 필요하다고 가정해 보겠습니다. 간단히 할 수 있습니다.
@staticmethod def validate_name(name): return len(name) <= 20
class name
사용하여 간단히 호출할 수 있습니다.
Person.validate_name("Gaurang Shah")
Gaurang Shah
더 나은 질문은 "언제 @classmethod
대 @staticmethod
를 사용하시겠습니까?"라고 생각합니다.
@classmethod
사용하면 클래스 정의와 연결된 비공개 멤버에 쉽게 액세스할 수 있습니다. 이것은 생성된 개체의 인스턴스 수를 제어하는 팩토리 클래스 또는 싱글톤을 수행하는 좋은 방법입니다.
@staticmethod
는 약간의 성능 향상을 제공하지만 클래스 외부에서 독립 실행형 함수로 달성할 수 없는 클래스 내에서 정적 메서드를 생산적으로 사용하는 것을 아직 보지 못했습니다.
Nathan Tregillus
정적 메서드:
- 자체 인수가 없는 간단한 함수.
- 클래스 속성에 대한 작업 인스턴스 속성이 아닙니다.
- 클래스와 인스턴스를 통해 호출할 수 있습니다.
- 내장 함수 staticmethod()를 사용하여 생성합니다.
정적 메서드의 이점:
- 클래스 범위에서 함수 이름을 현지화합니다.
- 기능 코드를 사용 위치에 더 가깝게 이동합니다.
각 메서드를 특별히 가져올 필요가 없으므로 모듈 수준 함수보다 가져오기가 더 편리합니다.
@staticmethod def some_static_method(*args, **kwds): pass
수업 방법:
- 클래스 이름으로 첫 번째 인수가 있는 함수.
- 클래스와 인스턴스를 통해 호출할 수 있습니다.
이것들은 classmethod 내장 함수로 생성됩니다.
@classmethod def some_class_method(cls, *args, **kwds): pass
Laxmi
첫 번째 인수만 다릅니다 .
- normal method: 현재 객체 가 자동으로 (추가) 첫 번째 인수로 전달됩니다.
- classmethod: 현재 객체의 클래스 가 자동으로 (추가) 첫 번째 인수로 전달됩니다.
- staticmethod: 추가 인수 가 자동으로 전달되지 않습니다. 당신이 함수에 전달한 것이 당신이 얻는 것입니다.
더 자세하게...
정상적인 방법
모든 객체 지향 언어에서와 같이 "표준" 방법. 개체의 메서드가 호출되면 자동으로 첫 번째 인수로 self
즉, 방법
def f(self, x, y)
2개의 인수로 호출해야 합니다. self
는 자동으로 전달 되며 객체 자체 입니다. 예를 들어 마술처럼 나타나는 this
과 유사합니다. java/c++에서는 python에서만 명시적으로 표시됩니다.
실제로, 첫 번째 인수를 호출 할 필요가 없습니다
self
만 표준 규칙, 그래서 그것을 유지
클래스 메소드
메소드를 장식할 때
@classmethod def f(cls, x, y)
자동으로 제공되는 인수가없는 self
만의 클래스 self
.
정적 메서드
메소드를 장식할 때
@staticmethod def f(x, y)
이 메서드에는 자동 인수 가 전혀 제공되지 않습니다. 호출되는 매개변수만 제공됩니다.
사용법
-
classmethod
는 대체 생성자에 주로 사용됩니다. -
staticmethod
는 객체의 상태나 클래스 자체의 구조를 사용하지 않습니다. 클래스 외부의 함수일 수 있습니다.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)
blue_note
@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와 static 메서드를 사용하는 좋은 예입니다. 정적 메서드는 내부적으로 Cluster 클래스를 사용하기 때문에 분명히 클래스에 속합니다. classmethod는 클래스에 대한 정보만 필요하고 객체의 인스턴스는 필요하지 않습니다.
_is_cluster_for
메소드를 classmethod로 만드는 또 다른 이점은 서브클래스가 구현을 변경할 수 있다는 점입니다. 아마도 이것이 매우 일반적이고 둘 이상의 클러스터 유형을 처리할 수 있기 때문일 수 있습니다. 따라서 클래스 이름을 확인하는 것만으로는 충분하지 않을 것입니다.
Jens Timmerman
@classmethod와 @staticmethod로 장식된 메소드의 유사점을 먼저 말씀드리겠습니다.
유사성: 둘 다 클래스 의 인스턴스 가 아니라 클래스 자체에서 호출될 수 있습니다. 따라서 둘 다 어떤 의미에서는 Class 의 메소드 입니다.
차이점: 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',)
Selva
@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'>
Armin Ronacher
Python에서 정적, 클래스 또는 추상 메서드를 사용하는 방법에 대한 최종 가이드 는 이 주제에 대한 좋은 링크 중 하나이며 다음과 같이 요약합니다.
@staticmethod 함수는 클래스 내부에 정의된 @staticmethod
클래스를 먼저 인스턴스화하지 않고 호출할 수 있습니다. 정의는 상속을 통해 변경할 수 없습니다.
- Python은 객체에 대한 바인딩 메서드를 인스턴스화할 필요가 없습니다.
- 코드의 가독성을 높이고 객체 자체의 상태에 의존하지 않습니다.
@classmethod
함수도 클래스를 인스턴스화하지 않고 호출할 수 있지만 해당 정의는 상속을 통해 상위 클래스가 아닌 하위 클래스를 따르므로 하위 클래스에서 재정의할 수 있습니다. @classmethod
함수의 첫 번째 인수는 항상 cls (클래스)여야 하기 때문입니다.
- 예를 들어 일종의 사전 처리를 사용하여 클래스의 인스턴스를 만드는 데 사용되는 팩토리 메서드.
- 정적 메서드를 호출하는 정적 메서드 : 정적 메서드를 여러 정적 메서드로 분할하는 경우 클래스 이름을 하드 코딩하지 말고 클래스 메서드를 사용해야 합니다.
zangw
staticmethod 대 classmethod와 관련된 또 다른 고려 사항은 상속과 관련이 있습니다. 다음과 같은 클래스가 있다고 가정합니다.
class Foo(object): @staticmethod def bar(): return "In Foo"
그런 다음 자식 클래스에서 bar()
를 재정의하려고 합니다.
class Foo2(Foo): @staticmethod def bar(): return "In Foo2"
이것은 작동하지만 이제 자식 클래스( Foo2
bar()
구현은 더 이상 해당 클래스와 관련된 어떤 것도 이용할 수 없습니다. 예를 들어, 말을 Foo2
방법이라고했다 magic()
당신이에서 사용하도록 Foo2
구현 bar()
:
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"
여기에서 해결 방법은 bar()
Foo2.magic()
을 호출하는 것이지만, 스스로 반복하는 것입니다( 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
또한: 역사적 메모: Guido Van Rossum(Python 작성자)은 한 번 staticmethod
를 "사고" 라고 언급했습니다. https://mail.python.org/pipermail/python-ideas/2012-May/014969.html
우리 모두는 정적 메서드가 얼마나 제한된지 압니다. (그들은 기본적으로 사고입니다. 제가 새로운 스타일의 클래스와 디스크립터를 발명하던 Python 2.2일 때, 저는 클래스 메소드를 구현하려고 했지만 처음에는 그것들을 이해하지 못하고 실수로 먼저 정적 메소드를 구현했습니다. 그런 다음 그것들을 제거하고 클래스 메소드만 제공하기에는 너무 늦었습니다.
또한: https://mail.python.org/pipermail/python-ideas/2016-July/041189.html
솔직히 말해서, staticmethod는 일종의 실수였습니다. 저는 Java 클래스 메소드와 같은 것을 하려고 시도했지만 일단 릴리스되고 나서 정말 필요한 것은 classmethod라는 것을 알았습니다. 그러나 staticmethod를 없애기에는 너무 늦었습니다.
Adam Parkin
나는 예제를 사용하여 기본적인 차이점을 설명하려고 노력할 것입니다.
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 Ax # 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 - 초기화하지 않고 static 및 classmethods를 직접 호출할 수 있습니다.
# A.run_self() # wrong A.run_static() A.run_class()
2- 정적 메서드는 자체 메서드를 호출할 수 없지만 다른 정적 및 클래스 메서드를 호출할 수 있습니다.
3- 정적 메서드는 클래스에 속하며 개체를 전혀 사용하지 않습니다.
4- 클래스 메소드는 객체에 바인딩되지 않고 클래스에 바인딩됩니다.
Rizwan Mumtaz
@classmethod : 여러 사용자가 레코드를 업데이트하는 것과 같이 해당 클래스에서 생성된 모든 인스턴스에 대한 공유 전역 액세스를 생성하는 데 사용할 수 있습니다. 특히 싱글톤을 생성할 때도 유용하다는 것을 알았습니다. )
@static 메서드: 연결된 클래스 또는 인스턴스와 아무 관련이 없습니다. 하지만 가독성을 위해 정적 메서드를 사용할 수 있습니다.
vijay
클래스 메소드는 인스턴스 메소드가 인스턴스를 수신하는 것처럼 클래스를 암시적 첫 번째 인수로 수신합니다. 그것은 클래스의 객체가 아니라 클래스에 바인딩된 메서드입니다. 객체 인스턴스가 아닌 클래스를 가리키는 클래스 매개변수를 취하기 때문에 클래스의 상태에 액세스할 수 있습니다. 클래스의 모든 인스턴스에 적용되는 클래스 상태를 수정할 수 있습니다. 예를 들어 모든 인스턴스에 적용할 클래스 변수를 수정할 수 있습니다.
반면에 정적 메서드는 클래스 메서드나 인스턴스 메서드에 비해 암시적인 첫 번째 인수를 받지 않습니다. 그리고 클래스 상태에 액세스하거나 수정할 수 없습니다. 디자인 관점에서 올바른 방법이기 때문에 클래스에만 속합니다. 그러나 기능 면에서 런타임 시 클래스에 바인딩되지 않습니다.
지침으로 정적 메서드를 유틸리티로 사용하고 클래스 메서드를 예를 들어 factory 로 사용합니다. 또는 싱글톤을 정의할 수도 있습니다. 그리고 인스턴스 메서드를 사용하여 인스턴스의 상태와 동작을 모델링합니다.
내가 분명했기를 바랍니다!
Nicolae Petridean
다음과 같은 차이점을 고려할 수 있습니다.
class A: def foo(): # no self parameter, no decorator pass
그리고
class B: @staticmethod def foo(): # no self parameter pass
이것은 python2와 python3 사이에서 변경되었습니다.
파이썬2:
>>> A.foo() TypeError >>> A().foo() TypeError >>> B.foo() >>> B().foo()
파이썬3:
>>> A.foo() >>> A().foo() TypeError >>> B.foo() >>> B().foo()
따라서 클래스에서 직접 호출되는 메서드에만 @staticmethod
를 사용하는 것은 python3에서 선택 사항이 되었습니다. 클래스와 인스턴스 모두에서 호출하려면 @staticmethod
데코레이터를 사용해야 합니다.
다른 경우는 unutbus 답변으로 잘 다루어졌습니다.
David Schumann
차이는 상속이 있을 때 발생합니다.
부모와 자식이라는 두 개의 클래스가 있다고 가정합니다. @staticmethod를 사용하려면 클래스 이름을 인쇄 라인에 써야 하므로 print_name 메소드를 두 번 작성해야 합니다.
class Parent: _class_name = "Parent" @staticmethod def print_name(): print(Parent._class_name) class Child(Parent): _class_name = "Child" @staticmethod def print_name(): print(Child._class_name) Parent.print_name() Child.print_name()
그러나 @classmethod의 경우에는 print_name 메소드를 두 번 작성할 필요가 없습니다.
class Parent: _class_name = "Parent" @classmethod def print_name(cls): print(cls._class_name) class Child(Parent): _class_name = "Child" Parent.print_name() Child.print_name()
H.H
@staticmethod
호출할 수 있는 방법을 포함하여 @classmethod
, @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) ''' """
Michael Swartz
인스턴스 방법 :
+
개체 인스턴스 상태를 수정할 수 있습니다.
+
클래스 상태를 수정할 수 있습니다.
수업 방법 :
-
개체 인스턴스 상태를 수정할 수 없습니다.
+
클래스 상태를 수정할 수 있습니다.
정적 방법 :
-
개체 인스턴스 상태를 수정할 수 없습니다.
-
클래스 상태를 수정할 수 없음
class MyClass: ''' Instance method has a mandatory first attribute self which represent the instance itself. Instance method must be called by a instantiated instance. ''' def method(self): return 'instance method called', self ''' Class method has a mandatory first attribute cls which represent the class itself. Class method can be called by an instance or by the class directly. Its most common using scenario is to define a factory method. ''' @classmethod def class_method(cls): return 'class method called', cls ''' Static method doesn't have any attributes of instances or the class. It also can be called by an instance or by the class directly. Its most common using scenario is to define some helper or utility functions which are closely relative to the class. ''' @staticmethod def static_method(): return 'static method called' obj = MyClass() print(obj.method()) print(obj.class_method()) # MyClass.class_method() print(obj.static_method()) # MyClass.static_method()
산출:
('instance method called', <__main__.MyClass object at 0x100fb3940>) ('class method called', <class '__main__.MyClass'>) static method called
우리가 실제로 객체 인스턴스에 접근할 수 있는 인스턴스 메소드가 있습니다. 그래서 이것은 내 클래스 객체의 인스턴스였습니다. 반면에 클래스 메소드를 사용하면 클래스 자체에 접근할 수 있습니다. 그러나 클래스 메소드는 존재하는 객체에 대해 실제로 신경 쓰지 않기 때문에 객체 중 어느 것도 아닙니다. 그러나 개체 인스턴스에서 클래스 메서드와 정적 메서드를 모두 호출할 수 있습니다. 이것은 작동할 것이므로 실제로 차이가 없으므로 여기에서 정적 메소드를 호출하면 작동할 것이며 호출하려는 메소드를 알게 될 것입니다.
정적 메서드는 일부 유틸리티 작업을 수행하는 데 사용되며 클래스 메서드는 팩토리 메서드에 사용됩니다. 팩토리 메소드는 다양한 사용 사례에 대해 클래스 객체를 반환할 수 있습니다.
마지막으로 더 나은 이해를 위한 짧은 예:
class Student: def __init__(self, first_name, last_name): self.first_name = first_name self.last_name = last_name @classmethod def get_from_string(cls, name_string: str): first_name, last_name = name_string.split() if Student.validate_name(first_name) and Student.validate_name(last_name): return cls(first_name, last_name) else: print('Invalid Names') @staticmethod def validate_name(name): return len(name) <= 10 stackoverflow_student = Student.get_from_string('Name Surname') print(stackoverflow_student.first_name) # Name print(stackoverflow_student.last_name) # Surname
Milovan Tomašević
@staticmethod를 분석하여 말 그대로 다양한 통찰력을 제공합니다.
클래스의 일반 메서드는 인스턴스를 첫 번째 인수로 사용 하는 암시적 동적 메서드입니다.
대조적으로, 정적 메서드는 인스턴스를 첫 번째 인수로 사용하지 않으므로 '정적' 이라고 합니다.
staticmethod는 실제로 클래스 정의 외부의 것과 동일한 정상적인 기능입니다.
운 좋게도 클래스에 그룹화되어 적용되는 위치에 더 가까이 서거나 스크롤하여 찾을 수 있습니다.
AbstProcDo
순수 Python 버전의 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
Jacky1205
클래스 메서드는 이름에서 알 수 있듯이 객체가 아닌 클래스를 변경하는 데 사용됩니다. 클래스를 변경하려면 클래스 속성(객체 속성이 아님)을 수정합니다. 이것이 클래스를 업데이트하는 방법이기 때문입니다. 이것이 클래스 메소드가 클래스(일반적으로 '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. Eg Some global variable/function."
Tushar Vazirani
한 가지 매우 중요한 실제 차이점은 하위 분류할 때 발생합니다. 괜찮으시다면 @unutbu의 예를 도용하겠습니다.
class A: 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) class B(A): pass
class_foo
에서 메서드는 호출된 클래스를 알고 있습니다.
A.class_foo(1) # => executing class_foo(<class '__main__.A'>, 1) B.class_foo(1) # => executing class_foo(<class '__main__.B'>, 1)
static_foo
에서는 A
B
에서 호출되는지 확인할 방법이 없습니다.
A.static_foo(1) # => executing static_foo(1) B.static_foo(1) # => executing static_foo(1)
staticmethod
에서 다른 메소드를 사용할 수 없다는 것을 의미하는 것이 아니라, 당신은 단지 클래스를 직접 참조해야 한다는 것을 의미합니다.
class A: @classmethod def class_qux(cls, x): print(f"executing class_qux({cls}, {x})") @classmethod def class_bar(cls, x): cls.class_qux(x) @staticmethod def static_bar(x): A.class_qux(x) class B(A): pass A.class_bar(1) # => executing class_qux(<class '__main__.A'>, 1) B.class_bar(1) # => executing class_qux(<class '__main__.B'>, 1) A.static_bar(1) # => executing class_qux(<class '__main__.A'>, 1) B.static_bar(1) # => executing class_qux(<class '__main__.A'>, 1)
Ale
먼저 두 개념을 모두 이해하는 데 사용할 예제 코드부터 시작하겠습니다.
class Employee: NO_OF_EMPLOYEES = 0 def __init__(self, first_name, last_name, salary): self.first_name = first_name self.last_name = last_name self.salary = salary self.increment_employees() def give_raise(self, amount): self.salary += amount @classmethod def employee_from_full_name(cls, full_name, salary): split_name = full_name.split(' ') first_name = split_name[0] last_name = split_name[1] return cls(first_name, last_name, salary) @classmethod def increment_employees(cls): cls.NO_OF_EMPLOYEES += 1 @staticmethod def get_employee_legal_obligations_txt(): legal_obligations = """ 1. An employee must complete 8 hours per working day 2. ... """ return legal_obligations
클래스 방식
클래스 메서드는 클래스 자체를 암시적 인수로 받아들이고 선택적으로 정의에 지정된 다른 인수를 받아들입니다. 클래스 메소드는 (인스턴스 메소드처럼) 객체 인스턴스에 접근할 수 없다는 것을 이해하는 것이 중요합니다. 따라서 클래스 메서드는 인스턴스화된 개체의 상태를 변경하는 데 사용할 수 없지만 대신 해당 클래스의 모든 인스턴스 간에 공유되는 클래스 상태를 변경할 수 있습니다. 클래스 메서드는 일반적으로 클래스 자체에 액세스해야 할 때 유용합니다. 예를 들어 팩토리 메서드를 만들려는 경우, 즉 클래스의 인스턴스를 만드는 메서드입니다. 즉, 클래스 메서드는 대체 생성자 역할을 할 수 있습니다.
예제 코드에서 Employee
의 인스턴스는 세 개의 인수를 제공하여 구성할 수 있습니다. first_name
, last_name
및 salary
.
employee_1 = Employee('Andrew', 'Brown', 85000) print(employee_1.first_name) print(employee_1.salary) 'Andrew' 85000
이제 이름과 성이 공백으로 구분된 단일 필드에 직원의 이름을 제공할 수 있는 가능성이 있다고 가정해 보겠습니다. 이 경우 총 3개의 인수를 허용하는 employee_from_full_name
이라는 클래스 메서드를 사용할 수 있습니다. 첫 번째는 클래스 자체입니다. 암시적 인수는 메서드를 호출할 때 제공되지 않음을 의미합니다. Python이 자동으로 이 작업을 수행합니다.
employee_2 = Employee.employee_from_full_name('John Black', 95000) print(employee_2.first_name) print(employee_2.salary) 'John' 95000
employee_from_full_name
을 호출하는 것도 가능하지만 이 컨텍스트에서는 그다지 의미가 없습니다.
employee_1 = Employee('Andrew', 'Brown', 85000) employee_2 = employee_1.employee_from_full_name('John Black', 95000)
클래스 메소드를 생성하려는 또 다른 이유는 클래스의 상태를 변경해야 할 때입니다. 이 예에서 클래스 변수 NO_OF_EMPLOYEES
는 현재 회사에서 일하는 직원 수를 추적합니다. 이 메서드는 Employee의 새 인스턴스가 생성될 때마다 호출되며 그에 따라 개수를 업데이트합니다.
employee_1 = Employee('Andrew', 'Brown', 85000) print(f'Number of employees: {Employee.NO_OF_EMPLOYEES}') employee_2 = Employee.employee_from_full_name('John Black', 95000) print(f'Number of employees: {Employee.NO_OF_EMPLOYEES}') Number of employees: 1 Number of employees: 2
정적 메서드
반면에 정적 메서드에서는 인스턴스(예: self
)도 클래스 자체(예: cls
)도 암시적 인수로 전달되지 않습니다. 이는 이러한 메서드가 클래스 자체 또는 해당 인스턴스에 액세스할 수 없음을 의미합니다. 이제 정적 메서드를 클래스의 구성원으로 추가하는 대신 도우미 모듈에 배치할 수도 있으므로 클래스 컨텍스트에서 정적 메서드가 유용하지 않다고 주장할 수 있습니다. 객체 지향 프로그래밍에서는 클래스를 논리적 청크로 구조화하는 것이 중요합니다. 따라서 정적 메서드는 논리적으로 클래스에 속하기 때문에 클래스 아래에 메서드를 추가해야 할 때 매우 유용합니다. 이 예에서 get_employee_legal_obligations_txt
라는 정적 메서드는 회사의 모든 단일 직원의 법적 의무가 포함된 문자열을 반환합니다. 이 함수는 클래스 자체 또는 인스턴스와 상호 작용하지 않습니다. 다른 도우미 모듈에 배치할 수도 있지만 이 클래스에만 관련이 있으므로 Employee 클래스 아래에 배치해야 합니다.
정적 메서드는 클래스 자체에서 직접 액세스할 수 있습니다.
print(Employee.get_employee_legal_obligations_txt()) 1. An employee must complete 8 hours per working day 2. ...
또는 클래스의 인스턴스에서:
employee_1 = Employee('Andrew', 'Brown', 85000) print(employee_1.get_employee_legal_obligations_txt()) 1. An employee must complete 8 hours per working day 2. ...
참고문헌
Giorgos Myrianthous
staticmethod는 상속 계층에서 개체, 클래스 또는 부모 클래스의 속성에 액세스할 수 없습니다. 객체를 생성하지 않고 클래스에서 직접 호출할 수 있습니다.
classmethod는 개체의 속성에 액세스할 수 없습니다. 그러나 상속 계층 구조에서 클래스 및 상위 클래스의 속성에 액세스할 수 있습니다. 객체를 생성하지 않고 클래스에서 직접 호출할 수 있습니다. self.<attribute(s)>
self.__class__.<attribute(s)>
에만 접근하는 일반 메소드와 동일합니다.
b=2
인 클래스가 있다고 생각하고 객체를 생성하고 이를 b=4
로 재설정합니다. Staticmethod는 이전 항목에 액세스할 수 없습니다. Classmethod이 할 수있는 액세스 .b==2
단지를 통해 cls.b
. self.b
를 통해 .b==4
및 self.__class__.b
를 통해 .b==2
모두에 액세스할 수 있습니다.
우리는 KISS 스타일을 따를 수 있습니다(간단하고 멍청하게 유지): staticmethods와 classmethods를 사용하지 마십시오. 클래스를 인스턴스화하지 않고 사용하지 마십시오. 객체의 속성인 self.attribute(s)
에만 액세스하십시오. 그런 식으로 OOP를 구현하는 언어가 있는데 나쁘지 않은 생각입니다. :)
mirek
Python에는 여러 내장 데코레이터가 있습니다. 큰 세 가지는 다음과 같습니다.
@classmethod @staticmethod @property
@classmethod 데코레이터는 클래스의 인스턴스로 호출하거나 클래스 자체에서 첫 번째 인수로 직접 호출할 수 있습니다.
@staticmethod 는 함수를 클래스에 넣는 방법입니다(논리적으로 클래스에 속하기 때문에). 동시에 클래스에 대한 액세스가 필요하지 않음을 나타냅니다.
다음 클래스를 고려해보자.
class DecoratorTest(object): def __init__(self): pass def doubler(self, x): print("running doubler") return x*2 @classmethod def class_doubler(klass, x): print("running doubler: %s" % klass) return x*2 @staticmethod def static_doubler(x): print("running quad") return x*2 decor = DecoratorTest()
어떻게 작동하는지 봅시다:
print(decor.doubler(5)) # running doubler # 10 print(decor.class_doubler(5)) # running doubler: <class '__main__.DecoratorTest'> # 10 print(DecoratorTest.class_doubler(5)) # running doubler: <class '__main__.DecoratorTest'> # 10 print(DecoratorTest.static_doubler(5)) # running doubler # 10 print(decor.static_doubler(5)) # running doubler # 10 print(decor.doubler) # <bound method DecoratorTest.doubler of <__main__.DecoratorTest object at 0x7f90e74fd150>> print(decor.class_doubler) # <bound method DecoratorTest.class_doubler of <class '__main__.DecoratorTest'>> print(decor.static_doubler) # <function DecoratorTest.static_doubler at 0x7f90e7447440>
illuminato
출처 : 여기를 클릭하세요
출처 : http:www.stackoverflow.com/questions/136097/difference-between-staticmethod-and-classmethod
'etc. > StackOverFlow' 카테고리의 다른 글
jQuery에서 확인란이 선택되어 있는지 어떻게 확인합니까? (0) | 2021.09.30 |
---|---|
GUID/UUID를 만드는 방법 (0) | 2021.09.30 |
요소를 가로로 가운데에 맞추는 방법 (0) | 2021.09.30 |
로컬 리포지토리 분기를 원격 리포지토리 HEAD와 동일하게 재설정 (0) | 2021.09.30 |
Google이 while(1)을 앞에 추가하는 이유는 무엇입니까? JSON 응답에? (0) | 2021.09.30 |