Backend/Python

Python에서 @staticmethod, @classmethod, instance method,개념 정리

amelia-suyeon 2024. 2. 16. 11:32

필자는 다른 프로젝트에서 @classmethod를 사용하는 것을 보았다. 

 

python에서는 자주 사용하지 않았는데, 이번 기회에 개념을 정리하고 SQLALchemy에 적용하기 위해 알아보았다.

 

먼저, method에는 크게, instance method, static method, class method가 있는데, 

그 중 가장 많이 쓰이는 instance method는 사실 우리가 가장 많이 사용하고 있었다.

 

먼저, Shape() 라는 클래스를 하나 만들었고, 클래스 변수를 선언했다.

-> 클래스 변수는 내외적으로 호출(Shape.cnt) 할 수 있다!

 

class Shape():
    # 클래스 변수
    cnt = 0
    
    def __init__(self,width,height):
        self.width = width
        self.height = height
        Shape.cnt += 1
    
    # 인스턴스 method
    def calculArea(self):
        area = self.width * self.height
        print(area, "area")
        return area

 

여기서 instance method는 calculArea인데 -> 인스턴스 변수에 접근 위해 -> 항상 첫번째 파라미터에 "self" 기입

 

(※ self 즉, 객체 자신을 의미함)

 

[인스턴스 변수]

1. 인스턴스 변수 == "self.변수명"  가 존재 

하나의 클래스로 여러개 객체 찍어내기 가능 ( 붕어빵 틀 <-> 붕어빵 처럼)

 

2. 각 객체별로 서로 다른 값을 가지는 변수

 

3. 내부에서는 "self.* "를 이용해서 접근, 외부 = 객체변수.인스턴스변수 로 접근

 

4. 만약 private 하게 사용하고 싶다면 변수명 앞에 밑줄 두개(__)를 붙여준다. (함수도 마찬가지)

 

 

[초기화]

우리가 흔히  class를 생성하면, 아래에 바로 __init__()을 붙이는데, 클래스 intializer 라고 명명한다.

초기생성자는 객체를 만들때, 인스턴스 변수를 초기화 하거나, 객체 자체를 초기화 하기 위해 사용한다.

 

@staticmethod  vs  @classmethod

 

[static method 특징]

 

1. static method는 self 파라미터를 가지지 않는다.

 

2. self를 가지지 않기에, 인스턴스 변수에 접근 불가

 

3. 보통적으로 독립적일때 사용 (클래스 변수 접근 하지 않을때) -> 유틸리티성 이며, 어떤 변화를 일으키지 않고 항상 같은 값 출력을 위해 사용 

 

class Shape():
    cnt = 0
    
    def __init__(self,width,height):
        self.width = width
        self.height = height
        Shape.cnt += 1
    
    # 인스턴스 method
    def calculArea(self):
        area = self.width * self.height
        print(area, "area")
        return area 
    
    # static method
    @staticmethod
    def square(leftwidth, rightwidth):
        return leftwidth == rightwidth


a = Shape(2,4)
b = Shape(3,7)
c = Shape(200,2)

print("====== a,b,c, 객체 생성 및 함수 적용 ======")

a.calculArea()
b.calculArea()
c.calculArea()

print("====== a,b,c 기존에 각각 객체가 있는데 staticmethod 적용할 때 ======")

print(a.square(1,1))
print(b.square(2,1))
print(c.square(3,1))

print("====== 객체 생성하지 않고 바로 staticmethod 적용했을 때 ====== ")

print(Shape.square(3,1))
print(Shape.square(2,2))
print(Shape.square(3,1))

위와 같이 코드를 실행 했을 때, 객체 생성 유무에 따라서 테스트도 함께 해보았다.

그 결과는 아래와 같이 볼 수 있다. 

 

 

기존 a ,b ,c 객체를 생성해서 이미 값을 넣었지만,  square()함수에 넣은 매개변수에 따른 결과를 나타냄을 볼 수 있고, 객체 없이 클래스.함수로 호출해서 다시 다른 값을 넣었지만 이에 따른 결과 값이 도출되는 것을 볼 수 있다.

즉, 독립적으로 함수가 실행된다는 것을 알 수 있다.

 

 

[class method 특징]

 

1. static method와 비슷하지만, self 대신 cls를 사용한다.

 

2. cls를 통해서 클래스 변수에 접근 가능 (클래스 속성에 접근 할 때 자주 사용

 

아래의 클래스를 보면 이해가 될 것 이다. 

 

class Shape():
    cnt = 0
    
    def __init__(self,width,height):
        self.width = width
        self.height = height
        Shape.cnt += 1
    
    # 인스턴스 method
    def calculArea(self):
        area = self.width * self.height
        print(area, "area")
        return area 
    
    @classmethod
    def chg_cnt(cls, cnt):
        cls.cnt = cnt
        print(cnt, "cnt")
        
    @classmethod
    def calculCnt(cls, cnt2):
        print(cls.cnt, "cnt1")
        print(cls.cnt * cnt2, "result")
        return cls.cnt * cnt2


a = Shape(2,4)
b = Shape(3,7)

print("====== 객체 생성 후 classmethod 적용했을 때 ====== ")

a.chg_cnt(3)
b.chg_cnt(4)

print("====== 객체 없이 classmethod 적용했을 때 ====== ")

Shape.calculCnt(3)
Shape.calculCnt(4)
Shape.calculCnt(5)

 

여기도 마찬가지로 객체의 유무에 따라서 테스트 해보았다.

 

 

객체 없이 classmethod를 적용했을 때를 보면, 마지막으로 클래스 매서드인 chg_cnt 의 cnt  값을 상속받아서 결과 값이 보이는 것을 알 수 있다. 

 

이번에, 각각의 method를 정리하면서 헷갈리지 않고, 개념을 정립할 수 있어서 좋았다. 이를 바탕으로 SQLAlchemy에서 classmethod 를 적용한 부분을 다른 포스팅에 기록할 예정이다.