@classmethod는 다른 자식 클래스에서 @classmethod를 캡슐화 하는 클래스를 호출할 때 해당 메소드가 어떻게 작동해야 하는 지 정의하기 위해 사용된다. 반면 @staticmethod는 호출하는 child class에 관계 없이 같은 값을 리턴할 때 사용한다.
staticmethod는 staticmethod가 정의된 클래스 또는 객체에 대한 정보를 가지고 있지 않는 메소드로, 만약 정보를 갖도록 하고 싶다면 명시적으로 내용을 제공해야 한다.
다시 말해서, @staticmethod를 통해 정의된 메소드는 클래스 내에 정의된 일반 함수와 같은 것이라 볼 수 있다. 그렇기 때문에 보통의 클래스가 인자로 갖는 self
를 갖지 않는다. 또한, @staticmethod가 정의된 클래스(parent)를 상속 받아 사용하는 다른 클래스(child)에서 @staticmethod에 정의된 변수들을 변경하는 것 역시 불가능하다.
class Myclass():
@staticmethod
def mymethod():
print('static method called')
따라서, 위와 같이 정의된 클래스가 있을 때 Myclass
객체를 생성하지 않아도 mymethod
함수를 호출하는 것이 가능하다.
Myclass.mymethod()
→ 객체를 생성한 후 호출하려면 보통 아래와 같이 한다.
my_class = Myclass()
my_class.mymethod()
>>> 'static method called'
@staticmethod를 사용하면 클래스 내에 클래스 객체의 현재 상태와는 관계가 없는 함수를 생성할 수 있다. 그렇게 되면 클래스 내에서 반복되는 코드를 함수로 만들어 사용할 수 있어 가독성이 높은 코드를 작성할 수 있게 되며 외부에서 함수를 임포트 해와서 사용하는 번거로움 역시 줄일 수 있다.
클래스를 정의하면 보통 해당 클래스에 대한 객체를 선언하고, 생성된 인스턴스의 속성을 사용하게 된다. 그러나 @classmethod를 사용하면 특정 인스턴스가 아니라 해당 클래스 내에서 해당 메소드를 감싸는(캡슐화 하고 있는) 클래스를 불러와 그 속성을 사용할 수 있다. @classmethod는 호출된 클래스의 모든 속성에 접근이 가능한 클래스의 메소드라 볼 수 있다. 말이 참 복잡하긴 하다.
@classmethod를 사용하기 위해는 첫 번째 인자로 꼭 cls
를 넘겨 주어야 한다.
class MyClass:
@classmethod
def myclass(cls):
print('Class method called')
@classmethod도 @staticmethod와 마찬가지로 객체를 생성하지 않고도 호출하는 것이 가능하다.
Myclass.myclass()
@classmethod는 특정 인스턴스에 국한되지 않은 메소드가 필요할 때 사용한다. 그러나, @classmethod는 상속이 가능하며 subclass에 의해 override될 수 있다.
아래와 같이 MyClass를 정의한 뒤 ChildClass에서 ParentClass를 상속 받아 사용한다고 해보자.
class ParentClass():
TOTAL = 0
def __init__(self):
ParentClass.TOTAL = ParentClass.TOTAL+1
@classmethod
def get_total(cls):
print("Total: ",cls.TOTAL)
# Creating objects of parent class
parent1 = MyClass() # Total: 1
parent2 = MyClass() # Total: 2
# Creating a child class
class ChildClass(ParentClass):
TOTAL = 0
pass
ChildClass.get_total() # Total: 0
이 경우, parent1과 parent2는 각각 1씩 더해진 값이 리턴된다.
그러나, ChildClass
에서 ParentClass
를 상속 받기는 했지만 TOTAL의 값이 0으로 바뀌었다. 위에서 ParentClass
객체의 TOTAL이 2가 되었음에도 ChildClass
에서 0으로 변경해 버렸기 때문에 아무리 상속 받았다 할지라도 overriding 되어 TOTAL은 0이 되는 것이다.
이렇게만 봐서는 클래스메소드가 사실 잘 이해가 되지 않아 조금 더 찾아봤더니 아래와 같은 설명을 찾아볼 수 있었다.
하나의 클래스로부터 여러 객체 인스턴스를 생성해서 사용할 수 있다. 클래스 변수가 하나의 클래스에 하나만 존재하는 반면, 인스턴스 변수는 각 객체 인스턴스마다 별도로 존재한다.
정리하면, 클래스 변수는 여러 객체가 생성되어도 모든 객체가 공통으로 공유하는 반면, 인스턴스는 각 객체마다 별도로 가진다. 일반적으로 인스턴스 데이터에 엑세스 할 필요가 없는 경우 클래스 메서드나 정적 메서드를 사용하는데, 이 때 클래스 변수에 엑세스할 필요가 있을 때는 클래스 메서드를, 이에 엑세스할 필요가 없을 때는 정적 메서드를 사용한다.
참고
https://djangocentral.com/classmethod-and-staticmethod-explained/
https://www.tutorialsteacher.com/python/staticmethod-decorator
https://www.tutorialsteacher.com/python/classmethod-decorator
감사합니다 도움이 많이 되었어요!