함수 장식의 차이 무엇 @staticmethod
하나는 장식은 @classmethod
?
함수 장식의 차이 무엇 @staticmethod
하나는 장식은 @classmethod
?
답변:
의 호출 서명에 공지 사항을 차이를 : 어쩌면 예제 코드의 약간의 도움이 될 것입니다 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_foo
1 개의 인수를
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>
@staticmethod
서브 클래스로 재정 의하여 코드를 구성하는 데 도움 이 될 수 있습니다. 그것이 없으면 모듈 네임 스페이스에 떠 다니는 다양한 기능이 있습니다.
@staticmethod
하면 부스러기를 제거 할 수 있습니다. 파이썬으로 프로그래밍 언어를 구현하고 있습니다-라이브러리 정의 함수 execute
는 사용자 정의 함수에 인스턴스 인수 (예 : 함수 본문)가 필요한 정적 메소드를 사용합니다 . 이 데코레이터는 PyCharm 인스펙터에서 "사용하지 않은 매개 변수 자체"경고를 제거합니다.
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
>>>
공식 파이썬 문서 :
클래스 메서드는 인스턴스 메서드가 인스턴스를받는 것처럼 클래스를 암시 적 첫 번째 인수로받습니다. 클래스 메소드를 선언하려면 다음 관용구를 사용하십시오.
class C: @classmethod def f(cls, arg1, arg2, ...): ...
@classmethod
형태의 함수이다 장식 - 함수의 정의에 대한 설명을 참조 함수 정의 자세한.클래스 (등
C.f()
) 또는 인스턴스 (등) 에서 호출 할 수 있습니다C().f()
. 클래스를 제외하고 인스턴스는 무시됩니다. 파생 클래스에 대해 클래스 메서드가 호출되면 파생 클래스 개체가 암시 적 첫 번째 인수로 전달됩니다.클래스 메소드는 C ++ 또는 Java 정적 메소드와 다릅니다. 원하는
staticmethod()
경우이 섹션을 참조하십시오 .
정적 메소드는 내재 된 첫 번째 인수를받지 않습니다. 정적 메소드를 선언하려면 다음 관용구를 사용하십시오.
class C: @staticmethod def f(arg1, arg2, ...): ...
@staticmethod
형태의 함수이다 장식 - 함수의 정의에 대한 설명을 참조 함수 정의 자세한.클래스 (등
C.f()
) 또는 인스턴스 (등) 에서 호출 할 수 있습니다C().f()
. 클래스를 제외하고 인스턴스는 무시됩니다.Python의 정적 메소드는 Java 또는 C ++에서 발견되는 메소드와 유사합니다. 고급 개념에 대해서는
classmethod()
이 섹션을 참조하십시오 .
다음은 이 질문에 짧은 기사입니다
@staticmethod 함수는 클래스 안에 정의 된 함수일뿐입니다. 클래스를 먼저 인스턴스화하지 않고 호출 할 수 있습니다. 상속을 통해 정의를 변경할 수 없습니다.
@classmethod 함수는 클래스를 인스턴스화하지 않고도 호출 할 수 있지만 그 정의는 상속을 통해 Parent 클래스가 아닌 Sub 클래스를 따릅니다. @classmethod 함수의 첫 번째 인수는 항상 cls (class) 여야하기 때문입니다.
@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
cls._counter
cls._counter
코드가 다른 클래스에 있거나 클래스 이름이 변경된 경우에도 여전히 유효합니다 . 수업 Apple._counter
에 따라 다릅니다 Apple
. 다른 클래스 또는 클래스 이름이 변경되면 참조 된 클래스를 변경해야합니다.
파이썬에서 @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
, string
Python 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
.
C ++로 프로그래밍 언어를 배우기 시작한 다음 Java와 Python으로 시작했습니다. 그래서이 질문은 각각의 간단한 사용법을 이해할 때까지 나에게 많은 영향을 미쳤습니다.
클래스 메소드 : Java와 달리 Python은 C ++에 생성자 오버로드가 없습니다. 그리고 이것을 달성하기 위해 당신은 사용할 수 있습니다 classmethod
. 다음 예는 이것을 설명합니다.
의 우리가 가지고 생각해 보자 Person
2 개 개의 인수를 취하는 클래스 first_name
와 last_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_name
20자를 초과하지 않는 유효성 검사가 필요하다고 가정 하면 간단히 수행 할 수 있습니다.
@staticmethod
def validate_name(name):
return len(name) <= 20
그리고 당신은 단순히 class name
Person.validate_name("Gaurang Shah")
def __init__(self, first_name, last_name="")
은 classmethod 대신 사용하는 것입니다 get_person
. 이 경우에도 결과는 동일합니다.
더 좋은 질문은 "@classmethod와 @staticmethod를 언제 사용 하시겠습니까?"입니다.
@classmethod를 사용하면 클래스 정의와 연결된 개인 멤버에 쉽게 액세스 할 수 있습니다. 이것은 생성 된 객체의 인스턴스 수를 제어하는 단일 클래스 또는 팩토리 클래스를 수행하는 좋은 방법입니다.
@staticmethod는 약간의 성능 향상을 제공하지만 클래스 외부에서 독립형 함수로 달성 할 수없는 클래스 내에서 정적 메소드를 생산적으로 사용하는 것을 아직 보지 못했습니다.
@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
메소드를 클래스 메소드 로 만들면 얻을 수있는 또 다른 이점은 서브 클래스가 구현을 변경하기로 결정할 수 있다는 것입니다. 아마도 일반적이고 여러 유형의 클러스터를 처리 할 수 있기 때문에 클래스 이름을 확인하는 것만으로는 충분하지 않습니다.
정적 방법 :
정적 메소드의 장점 :
각 메소드를 특별히 가져올 필요가 없으므로 모듈 레벨 함수보다 가져 오기가 더 편리합니다.
@staticmethod
def some_static_method(*args, **kwds):
pass
수업 방법 :
이들은 클래스 메소드 내장 함수로 작성됩니다.
@classmethod
def some_class_method(cls, *args, **kwds):
pass
@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'>
c = C(); c.foo()
AttributeError를 일으킨다 type(c).foo()
. 이것은 또한 기능으로 간주 될 수 있습니다-왜 당신이 원하는지 모르겠습니다.
파이썬에서 정적, 클래스 또는 추상 메소드를 사용하는 방법에 대한 결정적인 안내서 는이 주제에 대한 하나의 좋은 링크이며 다음과 같이 요약합니다.
@staticmethod
함수는 클래스 안에 정의 된 함수일뿐입니다. 클래스를 먼저 인스턴스화하지 않고 호출 할 수 있습니다. 상속을 통해 정의를 변경할 수 없습니다.
@classmethod
함수는 클래스를 인스턴스화하지 않고도 호출 가능하지만 그 정의는 상속을 통해 Parent 클래스가 아닌 Sub 클래스를 따릅니다. 상속을 통해 서브 클래스가 재정의 할 수 있습니다. @classmethod
함수 의 첫 번째 인수 는 항상 cls (클래스) 여야 하기 때문 입니다.
첫 번째 인수 만 다릅니다 .
더 자세하게...
객체의 메소드가 호출되면 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)
@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',)
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()
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"
여기서 해결 방법은을 호출 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
예제를 사용하여 기본적인 차이점을 설명하려고합니다.
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- 클래스 메소드는 객체가 아니라 클래스에 바인딩됩니다.
다음의 차이점을 고려할 수 있습니다.
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()
따라서 @staticmethod
python3에서는 클래스에서 직접 호출 된 메소드 만 사용 하는 것이 선택 사항이되었습니다. 클래스와 인스턴스에서 호출하려면 @staticmethod
데코레이터 를 계속 사용해야합니다 .
다른 경우는 unutbus 답변으로 잘 다루어졌습니다.
클래스 메서드는 인스턴스 메서드가 인스턴스를받는 것처럼 클래스를 암시 적 첫 번째 인수로받습니다. 클래스의 객체가 아닌 클래스에 바인딩 된 메소드이며 객체 인스턴스가 아닌 클래스를 가리키는 클래스 매개 변수를 취하므로 클래스의 상태에 액세스 할 수 있습니다. 클래스의 모든 인스턴스에 적용되는 클래스 상태를 수정할 수 있습니다. 예를 들어 모든 인스턴스에 적용 할 클래스 변수를 수정할 수 있습니다.
반면에 정적 메서드는 클래스 메서드 나 인스턴스 메서드와 비교하여 암시적인 첫 번째 인수를받지 않습니다. 클래스 상태에 액세스하거나 클래스 상태를 수정할 수 없습니다. 디자인 관점에서 올바른 방법이기 때문에 클래스에만 속합니다. 그러나 기능면에서 런타임에는 클래스에 바인딩되지 않습니다.
지침으로 정적 메소드를 유틸리티로 사용하고 클래스 메소드를 예를 들어 factory로 사용하십시오. 또는 싱글 톤을 정의 할 수도 있습니다. 또한 인스턴스 메소드를 사용하여 인스턴스의 상태와 동작을 모델링하십시오.
희망이 분명했다!
내 기여 사이의 차이 보여 @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)
'''
"""
이름에서 알 수 있듯이 클래스 메서드는 객체가 아닌 클래스를 변경하는 데 사용됩니다. 클래스를 변경하려면 클래스를 업데이트하는 방식이므로 클래스가 클래스 속성 (개체 속성이 아님)을 수정합니다. 이것이 클래스 메소드가 클래스 (일반적으로 '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."
나는 순수하게 파이썬 버전을주고 생각 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
staticmethod는 상속 계층에서 객체, 클래스 또는 부모 클래스의 속성에 액세스 할 수 없습니다. 객체를 만들지 않고 클래스에서 직접 호출 할 수 있습니다.
classmethod는 객체의 속성에 액세스 할 수 없습니다. 그러나 상속 계층 구조에서 클래스 및 상위 클래스의 속성에 액세스 할 수 있습니다. 객체를 만들지 않고 클래스에서 직접 호출 할 수 있습니다. 객체에서 호출되면 액세스하지 않고 액세스하는 일반 메소드와 동일 self.<attribute(s)>
합니다self.__class__.<attribute(s)>
만.
클래스가 있다고 생각 b=2
하면 객체를 만들고 객체를 다시 설정 b=4
합니다. 정적 메소드는 이전의 아무것도 액세스 할 수 없습니다. Classmethod는을 .b==2
통해서만 액세스 할 수 있습니다 cls.b
. 일반 방법은 .b==4
via self.b
와 .b==2
via 모두에 액세스 할 수 있습니다 self.__class__.b
.
우리는 KISS 스타일을 따를 수있다 self.attribute(s)
. OOP가 그런 식으로 구현되는 언어가 있으며 이것이 나쁜 생각은 아니라고 생각합니다. :)
iPython의 다른 방법과 동일한 방법을 빠르게 해킹하면 @staticmethod
하면 (나노초 단위로) 약간의 성능 향상 얻을 수 있지만 그렇지 않으면 기능을 수행하지 않는 것으로 보입니다. 또한 staticmethod()
컴파일하는 동안 (스크립트를 실행할 때 코드를 실행하기 전에 발생 하는) 메소드를 처리하는 추가 작업으로 인해 성능이 향상 될 수 있습니다 .
코드 가독성을 위해 @staticmethod
나노초가 계산되는 많은 작업에 메소드가 사용 되지 않는 한 피 하지 않을 것 입니다.