본문 바로가기

Hacks

@classmethod, @property

개요

데코레이터의 역할을 하는, @classmethod와 @property는 어떤 기능을 하는지 알아보자.

 

1. @classmethod

2. @property

3. 마무리

 

 

1. @classmethod

@classmethod를 사용한 결과

직관적으로 그냥 바로 classmethod를 사용하면 어떻게 함수를 사용할 수 있는지 확인해보자.

 

class Person:
    def __init__(self, name: str="Kang", age: int=20) -> None:
        self.name = name
        self.age = age

    @classmethod
    def cal_age(cls, year):
    	# cls가 받는 것은 객체가 아닌 클래스
        print(f"현재 나이: {cls(age=50).age}")
        return f"{(year - 2023)}년 뒤에는 {(year - 2023) + cls(age=50).age}살"
    
    @staticmethod
    def cal_age_2(self, year):
        print(f"현재 나이: {self.age}")
        return f"{(year - 2023)}년 뒤에는 {(year - 2023) + self.age}살"
    
    def cal_age_3(self, year):
        print(f"현재 나이: {self.age}")
        return f"{(year - 2023)}년 뒤에는 {(year - 2023) + self.age}살"
#P1 = Person()일 때

@classmethod
# P1.cal_age(2029)
현재 나이: 50
6년 뒤에는 56살


@staticmethod
# Person.cal_age_2(P1, 2029)
현재 나이: 20
6년 뒤에는 26살


# P1.cal_age_3(2029)
현재 나이: 20
6년 뒤에는 26살

 

언급하지 않기는 했지만, @staticmethod도 같이 사용을 해봤다.

 

일반적인 멤버 함수를 사용하면?

우선, 일반적인 멤버변수 형식인 데코레이터가 없는 cal_age_3을 보자.

self 포인터를 통해서 호출하는 객체가 가지고 있는 나이 정보에 접근하고 있다.

즉, 호출하고 있는 객체인 "P1"이 self 포인터에 지정이 되어서 P1의 age에 접근을 하고 있다. 그리고 그 정보를 반환해주고 있다.

 

 

@staticmethod를 사용하면?

잠깐 일반적인 멤버 함수를 사용하는 코드를 봐보자.

필요한 argument로는 self가 존재하지만 사용할 때는 따로 괄호 안에 넣어서 객체를 전달해주지는 않는다.

 

왜냐하면, 알아서 self 자리가 P1으로 채워지기 때문이다.

 

하지만, @staticmethod를 데코레이터로 지정해주면 위와 같이 사용할 수 없게 된다.

@staticmethod 데코레이터가 존재한다는 것을 제외하고는 모두 같다.

하지만, 똑같은 방법으로 사용하면 아래와 같은 에러가 난다.

따라서, @staticmethod를 지정해서 사용해주려면 호출하는 클래스와 전달할 객체를 명시해주어야 한다.

아래와 같아야 한다.

물론,  Person 자리에 객체가 들어가도 상관은 없다.

대신 인자로 넘겨줄 self에는 무조건 객체가 들어가야 한다.

 

 

@classmethod를 사용하면?

우선, 입력으로 들어가는 게 다르다. 일부러 age 정보를 바꿨다. 이렇게 일부러 정보를 바꿔준 이유는,

cls에 들어가게 되는 것은 이 메소드를 호출하는 객체의 클래스이기 때문에 이를 보여주기 위해서였다..

 

말이 어렵지만, 결국 이 메소드를 호출하는 코드는 아래와 같다.

즉, 일반적인 메소드를 선언했을 때와 호출 방법이 같다.

하지만, 함수 내에 들어오는 것이 다르다.

데코레이터가 없는 일반적인 메소드는 cls 자리에 해당 메소드를 호출한 객체 정보가 들어온다.

그러나, classmethod를 사용하면 cls 자리에 해당 메소드를 호출한 객체의 클래스 정보가 들어온다.

 

그렇기 때문에 위와 같이 cls(age=50)처럼 적어준다면, age가 50인 객체가 생성되어 그 정보에 접근하게 되는 것이다.

 

 

2. @property

@property를 사용한 결과

이것도 마찬가지로 결과가 어떻게 나오는지 바로 확인해보자.

class Person:
    def __init__(self, name: str="Kang", age: int=20) -> None:
        self.name = name
        self.age = age
    
    @property
    def name(self):
        return self._name
    
    @name.setter
    def name(self, name):
        self._name = name
    
    @property
    def age(self):
        return self._age
    
    @age.setter
    def age(self, age):
        self._age = age
        

P1 = Person()
P2 = Person("Song", 10)
# P1.name, P1.age
Kang, 20


# P2.name, P2.age
Song, 10

사실상 결과만 봐도 일반적인 getter, setter와는 차이가 있다.

즉, @property를 사용하면 우리는 정의한 멤버 변수에 접근할 때 메소드처럼 접근할 수가 있게 되는 것이다!

 

 

3. 마무리

오늘은 이렇게 데코레이터에 포함되는 요소들인 @classmethod, @staticmethod, @property에 대해서 알아보았다.

이를 이용한다면, 파이썬 코드를 더욱 파이썬 답게 만들 수 있을 것이며, 한층 더 깔끔한 코드를 작성할 수 있을 것이다.