본문 바로가기
코딩 연습/코딩배우기

[python] 파이썬 스태틱(static) 메서드와 클래스(class) 메서드

by good4me 2020. 9. 17.

goodthings4me.tistory.com

 

■ 클래스의 인스턴스(객체)별로 존재하는 변수를 인스턴스 변수라고 하며, 인스턴스(객체)에 속하지 않고 클래스에 속한 변수를 클래스 변수라고 한다.

class Simple:
    cv = 20  # 클래스 변수
    
    def __init__(self):
        self.iv = 10   # 인스턴스 변수, 객체별로 존재

s = Simple()
print(s.iv)  # 10  / 인스턴스 변수는 객체를 통해 접근함
#print(Simple.iv)  # AttributeError: type object 'Simple' has no attribute 'iv'

# 클래스 변수는 클래스 이름으로 접근 가능
print(Simple.cv)  # 20

# 객체를 통해서도 클래스 변수에 접근 가능
print(s.cv)  # 20


# 접근하는 변수가 객체에 없으면 그 객체의 클래스에 가서 변수를 찾기 때문에 객체를 통해서도 접근이 가능하나, 가급적 클래스 변수는 클래스 이름을 통해 접근을 권장함 

# 클래스 변수는 객체들이 사용한 공용 변수이다.

class Simple:
    count = 0  # Simple 클래스 변수, 생성된 객체의 수를 저장하는 변수
    def __init__(self):
        Simple.count += 1
    
    def get_count(self):
        return Simple.count


def main():
    s1 = Simple()
    print(s1.get_count())  # 1
    
    s2 = Simple()
    print(s2.get_count())  # 2
    
    s3 = Simple()
    print(s3.get_count())  # 3
    
    # 하나의 클래스 변수를 3개의 객체로 접근(어떤 객체로든지 접근 가능함)
    print(s1.get_count())  # 3
    
    # 클래스명으로 get_count() 접근 불가 --> 인자로 객체를 전달하면 가능
    print(Simple.get_count(s1))  # 3
    
main()

good4me.co.kr

 

■ 스태틱(static) 메서드와 클래스 메서드

  • 파이썬의 클래스에서 직접 접근할 수 있는 메서드로 staticmethod와 classmethod가 있다.
  • 파이썬에서는 타 언어와 달리 인스턴스(객체)에서도 staticmethod에 접근 가능하고, 스태틱 메서드는 객체별로 공유하는 메서드이다.
  • 인스턴스(객체) 메소드는 첫번째 인자로 객체 자신(self)을 입력하지만, classmethod는 클래스 자신(cls)을 입력하고, staticmethod는 인자가 없다.

 

# 스태틱 메서드(staticmethod)

위 코드에서 생성된 객체수를 확인하기 위해 get_count()를 만들었는데, 이는 객체를 생성한 후 생성된 객체를 통해 접근하고 있다. 객체를 생성하지 않고도 몇 개의 객체가 생성되었는지 확인 가능한 메서드가 스태틱메서드다.

class Simple:
    count = 0
    def __init__(self):
        Simple.count += 1
    
    def sm_get_count():  # 첫 인자로 self가 없는 메서드 (static 메서드)
        print('static method!!')
        return Simple.count
    sm_get_count = staticmethod(sm_get_count)  # 스태틱 메서드로 만드는 방법


def main():
    print(Simple.sm_get_count()) # 0
    # 스태틱메서드는 객체가 없는 상태에서도 객체의 현재 수를 구할 수 있다.
    
    s1 = Simple()
    s2 = Simple()
    s3 = Simple()
    s4 = Simple()
    
    print(Simple.sm_get_count())  # static method!!, 4
    
    print(s1.sm_get_count())  # static method!!, 4
    
    # 스태틱 메서드는 클래스명 또는 객체로도 접근(호출) 가능 
    
main()

스태틱 메서드에 self가 없는 것은 그 메서드가 객체에 속하는 것이 아니라 클래스에 속한 메서드이기 떄문이다.
위 코드에서 스태틱 메서드로 만드는 sm_count = staticmethod(sm_count) 대신에 아래처럼 데코레이터 방법(@staticmethod)을 많이 사용한다.

@staticmethod
def sm_get_count():  # 첫 인자로 self가 없는 메서드 (static 메서드)
    print('static method!!')
    return Simple.count    

 

# 클래스 메서드(classmethod)

  • 스태틱 메서드를 만드는 데코레이터처럼 클래스 메서드도 데코레이터로 만든다.
  • 스태틱 메서드와 클래스 메서드의 외형적 차이는 첫번쨰 인자인 'cls'의 유무이다. ('cls' 말고 다른 단어로 해도 되지만, 관용적으로 사용하니 그냥 ~ ~)
  • 클래스 메서드의 호출 시 cls에 인자를 전달하지 않는다. 
class Simple:
    num = 5   # 클래스 변수
    
    @staticmethod
    def sm(i):
        print('static : 5 + {0} = {1}'.format(i, Simple.num + i))
    
    @classmethod    
    def cm(cls, i):  # 클래스 메서드
        print('class :5 + {0} = {1}'.format(i, Simple.num + i))

def main():
    Simple.sm(3)  # static : 5 + 3 = 8
    Simple.cm(3)  # class :5 + 3 = 8
    s = Simple()
    s.sm(4)  # static : 5 + 4 = 9
    s.cm(4)  # class :5 + 4 = 9
    
main()

클래스 메서드의 cls에 자동으로 전달되는 것은 그 메서드를 가진 클래스 자신이다.(파이썬은 클래스도 객체이기 때문에 인자로 전달 및 반환이 가능함)

class Simple:
    count = 0
    def __init__(self):
        Simple.count += 1
    
    @classmethod
    def get_count(cls):
        return cls.count  # cls에 전달되는 것은 Simple 클래스. ==Simple.count

def main():
    print(Simple.get_count())  # 0
    s = Simple()
    print(Simple.get_count())  # 1

main()

 

※ cls에 전달되는 것이 클래스이므로 이를 기반으로 객체를 생성할 수 있다.

class Natural:
    def __init__(self, n):
        self.n = n
    
    def get_n(self):
        return self.n
    
    @classmethod
    def add(cls, n1, n2):
        return cls(n1.get_n() + n2.get_n())  # ==Natural(n) 객체 생성 후 반환
    
def main():
    n1 = Natural(10)
    n2 = Natural(20)
    n3 = Natural.add(n1, n2)  # 클래스메서드 호출, 반환되는 객체를 n3에 저장
    print('{0} + {1} = {2}'.format(n1.get_n(), n2.get_n(), n3.get_n()))
    
main()

 

[클래스메서드 사용 예]

class Date:  # 날짜 표현 클래스
    def __init__(self, y, m, d):
        self.year = y
        self.month = m
        self.day = d
    
    def show(self):
        print('{0}. {1}. {2}'.format(self.year, self.month, self.day))
    
    @classmethod
    def next_day(cls, today):
        return cls(today.year, today.month, today.day + 1)
    

def main():
    d1 = Date(2020, 4, 5)
    d1.show()  # 2020. 4. 5
    d2 = Date.next_day(d1)  
    # cls(y, m, d) == Date(y, m, d) / 객체를 생성 후 반환
    d2.show()  # 2020. 4. 6

main()

 

[classmethod와 staticmethod 의 차이]

class Animal:
    language = '울음소리'
    
    def __init__(self):
        self.sound = '동물 울음소리 : ' + self.language
    
    @classmethod
    def cls_language(cls):
        return cls()
    
    @staticmethod
    def stc_language():
        return Animal()
    
    def show(self):
        print(self.sound)


class Dog(Animal):
    language = '멍멍'

a = Animal.cls_language()
b = Animal.stc_language()
print(a.show())  # 동물 울음소리 : 울음소리  /  부모클래스의 속성 값
print(b.show())  # 동물 울음소리 : 울음소리  /  부모클래스의 속성 값

c = Dog.cls_language()
d = Dog.stc_language()
print(c.show())  # 동물 울음소리 : 멍멍  /  cls 클래스의 속성 값
print(d.show())  # 동물 울음소리 : 울음소리  /  부모클래스의 속성 값

 

[참고 자료] 윤성우의 열혈파이썬 중급편

 

댓글