3 minute read

본 포스팅은 “윤성우의 열혈 파이썬 중급편” 책 내용을 기반으로 작성되었습니다. 잘못된 내용이 있을 경우 지적해 주시면 감사드리겠습니다.

25-1. 클래스 변수에 대한 이해

class Simple:
  def __init__(self):
    self.iv = 10   # iv는 인스턴스 변수(첫 대입 연산에서 생성되는 변수로써 객체별로 존재) 

s = Simple()
s.iv  # 인스턴스 변수는 개게 통해 접근!
(결과) 10
class Simple:
  cv = 20  # 클래스 변수! 클래스 Simple에 속하는 변수임
  def __init__(self):
    self.iv = 10

Simple.cv   # 클래스 변수는 클래스 이름으로 접근 가능!
s = Simple()
s.cv  # 클래스 변수는 객체를 통해서도 접근 가능!
s.iv
(결과) 20
       20
       10

클래스 변수는 인스턴스 변수랑 헷갈려보일 수 있음! 따라서 클래스 이름을 통해 접근하는 것을 권함

class Simple:
  count = 0
  def __init__(self):
    Simple.count += 1   # 클래스 내에서 클래스 변수에 접근하는 방법
  def get_count(self):
    return Simple.count

def main():
  s1 = Simple()
  print(s1.get_count())
  s2 = Simple() 
  print(s1.get_count())
  s3 = Simple()
  print(s1.get_count())

main()

(결과) 1 2 3

25-2. static 메소드

바로 위 예제에서 get_count 메소드를 호출하려면 객체가 있어야 한다.
static 메소드는 클래스에 속하는 메소드로, 객체 생성 없이 호출이 가능하다는 장점이 있다. 클래스 변수와 상당히 유사하다.

class Simple:
  def sm():
    print('static method')
  sm = staticmethod(sm)  # sm 메소드를 static 메소드로 만드는 방법!

def main():
  Simple.sm()  # static 메소드는 클래스 이름 통해 호출 가능하다!
  s = Simple()
  s.sm()       # static 메소드는 객체를 통해서도 호출 가능하다!

main()
(결과) static method
       static method

static 메소드와 인스턴스 메소드 차이는 첫번째 인자로 self를 전달 받지 못하냐, 받을 수 있냐에 있다.
클래스에 속한 메소드이니 당연히 self를 인자로 전달 받지 못한다.

위 예제의 코드를 보면 뭔가 떠오르는게 있지 않는가? sm = staticmethod(sm)
바로 전에 데코레이터에서 봤다!

class Simple:
  count = 0
  def __init__(self):
    Simple.count += 1
  
  @staticmethod
  def get_count():  # 매개변수 self가 없는 static 메소드 선언!
    return Simple.count

def main():
  print(Simple.get_count())
  s = Simple()
  print(Simple.get_count())

main()
(결과) 0
       1

25-3. class 메소드

class Simple:
  num = 5

  @staticmethod  # static 메소드 만들기 위한 데코레이터
  def sm(i):
    print('st~ 5 + {0} = {1}'.format(i, Simple.num+i))
  
  @classmethod  # class 메소드 만들기 위한 데코레이터
  def cm(cls, i):  # cls만 빼면 static 메소드와 동일!
    print('cl~ 5 + {0} = {1}'.format(i, Simple.num+i))

def main():
  Simple.sm(3)
  Simple.cm(3)
  s = Simple()
  s.sm(4)
  s.cm(4)

main()
(결과) st~ 5 + 3 = 8
       cl~ 5 + 3 = 8
       st~ 5 + 4 = 9
       cl~ 5 + 4 = 9

class 메소드는 cls인자를 갖는다는 것만 빼면 static 메소드와 동일하다. 그럼 cls 인자는 무엇을 의미할까?

class Simple:
  count = 0
  def __init__(self):
    Simple.count += 1

  @classmethod
  def get_count(cls):
    return cls.count  

def main():
  print(Simple.get_count())  # get_count의 cls에 전달되는 것은 Simple 클래스!
  s = Simple()
  print(Simple.get_count())

main()
(결과) 0
       1

보다시피 cls에 전달되는 것은 Simple 클래스이다! 즉, return cls.countreturn Simple.count가 되는 것이다!

다음처럼 클래스 메소드를 이용하여 객체를 생성할 수도 있다.

class Natural:
  def __init__(self, n):
    self.n = n
  def getn(self):
    return self.n
  
  @classmethod
  def add(cls, n1, n2):
    return cls(n1.getn() + n2.getn())

def main():
  n1 = Natural(1)
  n2 = Natural(2)
  n3 = Natural.add(n1, n2)
  print('{0} + {1} = {2}'.format(n1.getn(), n2.getn(), n3.getn()))

main()
(결과) 1 + 2 = 3

25-4. static 메소드보다 class 메소드가 더 어울리는 경우

class Date:
  def __init__(self, y, m, d):
    self.y = y
    self.m = m
    self.d = d
  
  def show(self):
    print('{0}, {1}, {2}'.format(self.y, self.m, self.d))
  
  @classmethod
  def next_day(cls, today):
    return cls(today.y, today.m, today.d + 1)

def main():
  d1 = Date(2025, 4, 5)
  d1.show()
  d2 = Date.next_day(d1)
  d2.show()

main()
(결과) 2025, 4, 5
       2025, 4, 6

위 예제에서 next_day 메소드는 새로운 객체 생성 및 반환하는 역할을 한다. 이러한 메소드를 ‘팩토리 메소드’라 한다. 클래스 메소드는 클래스 정보가 전달이 되기 때문에, 팩토리 메소드를 만드는데 매우 적합하다!

25-5. static 메소드보다 class 메소드가 완전 더 어울리는 경우

class Date:
  def __init__(self, y, m, d):
    self.y = y
    self.m = m
    self.d = d
  def show(self):
    print('{0}, {1}, {2}'.format(self.y, self.m, self.d))
  
  @classmethod
  def next_day(cls, today):
    return cls(today.y, today.m, today.d + 1)  # static 메소드로 구현하려 했다면, 조건문으로 두 개 만들어야...

class KDate(Date):
  def show(self):
    print('KOR: {0}, {1}, {2}'.format(self.y, self.m, self.d))

class JDate(Date):
  def show(self):
    print('JPN: {0}, {1}, {2}'.format(self.y, self.m, self.d))

def main():
  kd1 = KDate(2025, 4, 12)
  kd1.show()
  kd2 = KDate.next_day(kd1) # KDate가 cls로 넘어감
  kd2.show()
  jd1 = JDate(2027, 5, 19)
  jd1.show()
  jd2 = JDate.next_day(jd1) # JDate가 cls로 넘어감
  jd2.show()


main()
(결과) KOR: 2025, 4, 12
       KOR: 2025, 4, 13
       JPN: 2027, 5, 19
       JPN: 2027, 5, 20

Leave a comment