[python] @classmethod

- 6 mins

파이썬 클래스 메서드

가끔 코드를 보다가 클래스 내에서 @classmethod 라는 데커레이터를 사용하는 것을 보았다.

클래스에서 사용하는 일반 함수와 무슨 차이가 있을까?

  1 class MyClass:
  2     def my_doubler(self, num):
  3         print(num * 2)
  4
  5     @classmethod
  6     def my_doubler_class_method(cls, num):
  7         print(num * 2)

MyClass라는 클래스를 만들고, my_doubler, my_doubler_class_method 두 개의 함수를 정의했다.

두 함수 모두 전달받은 숫자에 2를 곱한 결과를 출력해주는 기능을 한다.

단, my_doubler_class_method 함수 위에는 @classmethod 라는 데커레이터를 붙여 클래스 메서드로 정의했다.


우선 일반적인 방식으로 클래스를 인스턴스화 하고, 함수를 사용해보자.

  1 class MyClass:
  2     def my_doubler(self, num):
  3         print(num * 2)
  4
  5     @classmethod
  6     def my_doubler_class_method(cls, num):
  7         print(num * 2)
  8
  9
 10 mc = MyClass()
 11 mc.my_doubler(10)  # 20
 12 mc.my_doubler_class_method(10)  # 20

(10) mc라는 변수로 MyClass 인스턴스를 생성하고,

(11~12) my_doublermy_doubler_class_method 에 10을 넣어 실행해보자.

두 경우 모두 ‘20’ 이라는 결과를 똑같이 반환한다.


그렇다면 클래스 메서드와 일반 메서드의 차이는 무엇일까?

클래스 메서드는 다음과 같이 인스턴스화 하지 않고 바로 호출 가능하다.

  1 class MyClass:
  2     def my_doubler(self, num):
  3         print(num * 2)
  4
  5     @classmethod
  6     def my_doubler_class_method(cls, num):
  7         print(num * 2)
  8
  9
 10 MyClass.my_doubler_class_method(10)  # 20

그럼 my_doubler 는 인스턴스화 하지 않고 호출이 불가능할까?

불가능하진 않지만, 다음과 같이 ‘self’ 자리에 들어갈 값을 임의로 넣어주어야한다.

  1 class MyClass:
  2     def my_doubler(self, num):
  3         print(num * 2)
  4
  5     @classmethod
  6     def my_doubler_class_method(cls, num):
  7         print(num * 2)
  8
  9
 10 MyClass.my_doubler(None, 10)  # 20

(11) 클래스 메서드인 my_doubler_class_method의 경우 cls에 들어가는 값을 생략할 수 있었지만,

일반 메서드인 my_doubler의 경우는 self에 들어가는 값을 생략할 수 없어서 None 이라는 임의의 값을 넣었다.

이 경우는 클래스 내의 다른 변수에 접근할 일이 없었기때문에 문제 없이 실행이 됐지만,

클래스 내의 특정 변수를 참고해야하는 경우에는 문제가 생긴다.

클래스에 변수를 추가해보자.

  1 class MyClass:
  2     print_format = "{} * 2 = {}"
  3     def my_doubler(self, num):
  4         print(self.print_format.format(num, num * 2))
  5
  6     @classmethod
  7     def my_doubler_class_method(cls, num):
  8         print(cls.print_format.format(num, num * 2))

이번엔 그냥 출력하는 것이 아니라 print_format 변수에 정해놓은 모양에 맞추어 결과를 출력해준다.

예를들어 my_doubler(10)'10 * 2 = 20' 이라는 문자열을 출력한다.


앞선 예제와 마찬가지로,

우선 일반적인 방식으로 클래스를 인스턴스화 하고, 함수를 사용해보자.

  1 class MyClass:
  2     print_format = "{} * 2 = {}"
  3     def my_doubler(self, num):
  4         print(self.print_format.format(num, num * 2))
  5
  6     @classmethod
  7     def my_doubler_class_method(cls, num):
  8         print(cls.print_format.format(num, num * 2))
  9
 10
 11 mc = MyClass()
 12 mc.my_doubler(10)  # 10 * 2 = 20
 13 mc.my_doubler_class_method(10)  # 10 * 2 = 20

(11) mc라는 변수로 MyClass 인스턴스를 생성하고,

(12~13) my_doublermy_doubler_class_method 에 10을 넣어 실행해보자.

두 경우 모두 ‘10 * 2 = 20’ 이라는 결과를 똑같이 반환한다.


이번에는 인스턴스화 하지 않은 상태로 바로 클래스 메서드를 사용해보자.

  1 class MyClass:
  2     print_format = "{} * 2 = {}"
  3     def my_doubler(self, num):
  4         print(self.print_format.format(num, num * 2))
  5
  6     @classmethod
  7     def my_doubler_class_method(cls, num):
  8         print(cls.print_format.format(num, num * 2))
  9
 10
 11 MyClass.my_doubler_class_method(10)  # 10 * 2 = 20

제대로 실행이 되었다.

즉, 클래스에 있는 print_format 변수를 가져다가 쓰는데 전혀 문제가 없다.

이번에는 일반 메서드인 my_doubler를 인스턴스화 하지 않고 사용해보자.

  1 class MyClass:
  2     print_format = "{} * 2 = {}"
  3     def my_doubler(self, num):
  4         print(self.print_format.format(num, num * 2))
  5
  6     @classmethod
  7     def my_doubler_class_method(cls, num):
  8         print(cls.print_format.format(num, num * 2))
  9
 10
 11 MyClass.my_doubler(None, 10)  # AttributeError: 'NoneType' object has no attribute 'print_format'

11번째 줄의 주석을 보자.

해당 스크립트를 실행한 결과 발생한 에러이다.

일반 메서드인 my_doubler 는 클래스메서드인 my_doubler_class_method와 달리 print_format 변수를 참조할 수 없다.

즉, 특정 메서드에 @classmethod 데커레이터를 붙여 클래스 메서드로 정의하게되면,

클래스를 인스턴스화 하지 않은 채 클래스 내부의 변수나 함수에 접근해 사용 가능하다.




코딩장이

코딩장이

-장이: [접사] ‘그것과 관련된 기술을 가진 사람’의 뜻을 더하는 접미사.

rss facebook twitter github youtube mail spotify lastfm instagram linkedin google google-plus pinterest medium vimeo stackoverflow reddit quora quora