파이썬/클래스와 객체 지향

파이썬에서 @property와 setter의 올바른 사용법

Data Jun 2025. 9. 6. 15:31

파이썬에서 **캡슐화(encapsulation)**를 구현할 때 가장 많이 쓰이는 도구 중 하나가 @property입니다.

이를 통해 객체의 속성에 안전하게 접근할 수 있고, 필요하다면 검증 로직까지 넣을 수 있습니다.

그런데 초보자분들이 자주 혼동하는 부분이 있습니다.
바로 "@property는 인스턴스 변수용인가, 클래스 변수에도 쓸 수 있는가?" 하는 문제입니다.

 

1. @property는 인스턴스 변수를 위한 기능

@property와 @속성이름.setter는 인스턴스 변수를 대상으로 동작합니다.
즉, 객체가 가지고 있는 self._변수를 감싸서 getter와 setter를 제공하는 방식입니다.

 

예시

class Car:
    def __init__(self, price):
        self._price = price   # 인스턴스 변수

    @property
    def price(self):          # getter
        return self._price

    @price.setter
    def price(self, value):   # setter
        if value < 0:
            raise ValueError("가격은 0 이상이어야 합니다.")
        self._price = value

사용 예시:

car = Car(1000)

print(car.price)  # getter 동작 → 1000

car.price = 2000  # setter 동작
print(car.price)  # 2000

car.price = -500  # ValueError 발생

외부에서는 car.price처럼 속성에 접근하지만, 내부적으로는 _price라는 인스턴스 변수가 보호되고 있습니다. 이것이 파이썬에서 말하는 캡슐화입니다.

 

2. setter는 반드시 property가 정의되어 있어야 한다

중요한 점은, setter는 @property가 먼저 정의되어 있어야만 사용 가능하다는 것입니다.

class Car:
    @price.setter   # ❌ 오류: 아직 price라는 property 없음
    def price(self, value):
        self._price = value

위 코드를 실행하면 NameError가 발생합니다.
@price.setter는 price라는 property 객체에 setter를 연결하려는 문법인데,
정작 @property def price(self)가 없으니 당연히 동작하지 않는 것이죠.

따라서 setter를 쓰려면 반드시 아래처럼 **getter(@property)**가 먼저 정의되어야 합니다.

class Car:
    def __init__(self, price):
        self._price = price

    @property
    def price(self):       # getter
        return self._price

    @price.setter
    def price(self, value):  # setter
        self._price = value

 

3. 클래스 변수에는 @property를 쓰지 않는다

많이 혼동하는 부분이 클래스 변수입니다.
예를 들어, 아래처럼 클래스 차원에서 공유되는 변수를 관리하고 싶을 수 있습니다.

class Car:
    price_per_raise = 1.0   # 클래스 변수

이런 경우에는 @property를 직접 붙이면 의도대로 동작하지 않습니다.
왜냐하면 @property는 기본적으로 **인스턴스 속성(self)**을 전제로 하기 때문입니다.

클래스 변수를 제어하고 싶다면 다음 두 가지 방법이 일반적입니다.

 

1️⃣ 방법 1. 클래스 메소드 사용

class Car:
    price_per_raise = 1.0

    @classmethod
    def set_price_per_raise(cls, per):
        if per <= 1:
            raise ValueError("1보다 큰 값을 넣어야 합니다.")
        cls.price_per_raise = per

 

2️⃣ 방법 2. 인스턴스 property에서 클래스 변수 참조

class Car:
    _price_per_raise = 1.0

    @property
    def price_per_raise(self):
        return self.__class__.price_per_raise

    @price_per_raise.setter
    def price_per_raise(self, per):
        if per <= 1:
            raise ValueError("1보다 큰 값을 넣어야 합니다.")
        self.__class__.price_per_raise = per

이렇게 하면 인스턴스에서 접근할 때 car.price_per_raise처럼 보이지만, 실제로는 클래스 변수(Car.price_per_raise)가 수정됩니다.

 

 

정리하면

  1. @property, @속성이름.setter는 인스턴스 변수 전용이다.
  2. setter는 반드시 @property가 먼저 정의되어 있어야 한다.
  3. 클래스 변수를 관리하려면 @classmethod를 쓰거나, property에서 self.__class__를 통해 우회 접근한다.

결론적으로, @property는 인스턴스 속성 캡슐화 도구이고, 클래스 변수 관리에는 맞지 않습니다