파이썬의 다양한 주제들을 접하다 보면, 어떤 기능이나 문법을 어떻게 사용하는지는 알 것 같은데 왜 그것을 그렇게 사용하는 것인지에 대한 묘한 찜찜함이 계속되는 경우가 종종 있습니다. 제게는 정적 메소드와 클래스 메소드가 그런 경우였습니다.
때문에 이 주제에 대해 생각이 날 때 마다 나름대로 많은 정보를 찾아 보았지만, 제가 찾은 많은 관련 자료들 역시 왜 그것을 그렇게 사용하느냐에 대한 설명 보다는 어떻게 사용하느냐에 국한된 경우가 많았습니다.
그러던 중 HAMA님의 블로그에서 관련 내용을 다시 접하게 될 기회가 생겼는데요, 제 나름대로는 해당 글 덕분에 어느정도 생각의 정리(혹은 타협)을 할 수 있었습니다.
여담이지만, 무엇보다도 제게 큰 위로가 되었던 대목은 전문가를 위한 파이썬의 저자인 루시아누 하말류 또한 아래와 같은 아래와 같은 말을 했다는 부분이었습니다.
@classmethod 는 쓰임새가 많은 게 확실하지만, @staticmethod 는 사용해야하는 이유를 잘 모르겠다. 클래스와 함게 작동하지 않는 함수를 정의하려면, 단지 함수를 모듈에 정의하면 된다. 아마 함수가 클래스를 건드리지는 않지만, 그 클래스와 밀접히 연관되어 있어서 클래스 코드 가까운 곳에 두고 싶을 수는 있을 것이다. 그런 경우에는 클래스의 바로 앞이나 뒤에서 함수를 정의하면 된다.
물론 개인적으로는 함수를 모듈 근처에 두는 것과 클래스 아래에 두는 것은 개발자의 의도를 코드로 표현함에 있어 분명히 차이가 있을 수 있다고 생각합니다만, 하지만 짧은 경험을 가진 제가 자세히 이야기 할 부분은 아닌 것 같습니다.
다만 바로 위 제 개인적인 생각과 그 동안 찾아보았던 정적 메소드와 클래스 메소드에 대한 다양한 논의들을 바탕으로 해당 문제는 대체로 아래와 같이 요약할 수 있다고 결론내리게 되었습니다.
@Staticmethod
A simple way of putting a function into a class while indicating that it does not require access to the class, but when it logically belongs there.
@Classmethod
Useful when the method to be a factory for the class even when subclass are involved.
클래스 메소드의 경우에는 조금 더 쉬운 이해를 위해 위에서 말씀드린 HAMA님의 블로그에서 소개된 사례를 조금 수정해보았습니다.
import datetime
class TimeStamp:
msg_header = "Timestamp: "
def __init__(self, ts):
self.msg = f"{self.msg_header}{ts}."
@classmethod
def c_prepare(cls):
return cls(datetime.datetime.now())
@staticmethod
def s_prepare():
return TimeStamp(datetime.datetime.now())
def show(self):
print(self.msg)
class Korean(TimeStamp):
msg_header = "타임스탬프: "
if __name__ == '__main__':
# Classmethod
TimeStamp.c_prepare().show()
Korean.c_prepare().show()
# Staticmethod
TimeStamp.s_prepare().show()
Korean.s_prepare().show()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
결과는 아래와 같습니다. 정적 메소드의 경우 우리가 원하던 결과를 얻지 못한 것을 알 수 있습니다.
Timestamp: 2018-10-19 14:56:44.104362
타임스탬프: 2018-10-19 14:56:44.104362
Timestamp: 2018-10-19 14:56:44.104362
Timestamp: 2018-10-19 14:56:44.104362
2
3
4