Python의 @property

클래스 중 @property의 데코레이터를 사용하면,
속성으로 검색할 수 있습니다.
class Point:
    def __init__(self, x, y):
        self._x = x
        self._y = y

    @property
    def x(self):
        return self._x 

    @property
    def y(self):
        return self._y

    @property
    def sum(self):
        return self._x + self._y

point = Point(10, 20)
print(point.x, point.y, point.sum)
# 10 20 30

이 상태에서 재대입하려고 해도 에러가 나옵니다.
x를 15로 바꾸려고 합니다.
point.x = 15

그러면 다음 오류가 발생합니다.



setter 설정



재대입으로 에러 표시시키지 않기 위해 setter를 설정해 갑니다.
class Point:
    def __init__(self, x, y):
        self._x = x
        self._y = y

    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

    @property
    def y(self):
        return self._y

    @y.setter
    def y(self, value):
        self._y = value

    @property
    def sum(self):
        return self._x + self._y

point = Point(10, 20)
print(point.x, point.y, point.sum)
# 10 20 30

이렇게 각 속성에서 setter를 준비하면 재대입이 가능해집니다.
point.x = 15
print(point.x, point.y, point.sum)
# 15 20 35

setter 설정을 제한



예를 들어 0보다 큰 값만 넣고 싶다면
아래와 같이 setter를 써 줍니다.
@x.setter
def x(self, value):
    if value <= 0:
        raise ValueError(f'xは0より大きい値にしてください。入力値:{value}')
    self._x = value

전체 코드는 다음과 같습니다.
class Point:
    def __init__(self, x, y):
        self._x = x
        self._y = y

    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, value):
        if value <= 0:
            raise ValueError(f'xは0より大きい値にしてください。入力値:{value}')
        self._x = value

    @property
    def y(self):
        return self._y

    @y.setter
    def y(self, value):
        self._y = value

    @property
    def sum(self):
        return self._x + self._y

하지만 이 방법을 사용하면 인스턴스에 오류가 표시되지 않습니다.
point = Point(-10, 20) # 負の値を入れてもエラーにならない
print(point.x, point.y, point.sum)

인스턴스에서 setter를 움직여 입력 제한을 만드는 방법은 다음과 같습니다.

인스턴스화 시점에 인수 제한을 구현하는 방법



부모 클래스를 작성해 상속시키면 인스턴스시의 인수도 판정해 줍니다.
class Meta:
    def __init__(self, x, y):
      self.x = x
      self.y = y

class Point(Meta):
    def __init__(self, x, y):
        super().__init__(x, y)

    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, value):
        if value <= 0:
            raise ValueError(f'xは0より大きい値にしてください。入力値:{value}')
        self._x = value

    @property
    def y(self):
        return self._y

    @y.setter
    def y(self, value):
        self._y = value

    @property
    def sum(self):
        return self._x + self._y

이렇게 설정하면 인스턴스 시간 인수에서 x에 음수 값을 전달하면 오류가 발생합니다.
# こちらは問題なく動く
point = Point(10, 20)
print(point.x, point.y, point.sum)
# 10 20 30

# 負の値を渡すとエラーになる
point = Point(-10, 20)
# ValueError: xは0より大きい値にしてください。入力値:-10

어떤 경우에 속성을 설정합니까?



이것은 완전히 스스로 생각한 내용이므로, 다를지도 모르는 전제로 읽어 주셨으면 합니다.

속성을 설정할 때 크게 두 가지가 있다고 생각합니다.
  • 참조 및 변경이 쉽게 가능합니다
  • 메소드 등으로 지정하지 않아도 변경하면 자동 계산되어 출력이 가능

  • 2에 관해서는 상기 예제의 sum의 예입니다.

    전제로서, 프로퍼티의 설정을 할 때는 setter 와 함께 사용하지 않으면 의미가 없습니다.
    왜냐하면 @property 를 설정하지 않아도 생성자의 내용은
    속성으로서 취득 가능하기 때문입니다.

    pandas의 예라면 DataFrame.columns를 알기 쉽다고 생각합니다.
    항목명을 바꿀 때는 아래와 같이 변경이 가능합니다.
    print(df.columns) #これで項目名一覧の取得が可能
    df.columns = ['new_col1', 'new_col2', 'new_col3']
    

    스스로 작성해 class에서도 활용하고 싶다고 생각하면서도 어떤 때에 사용하는지가
    명확하지 않았기 때문에 언어화해 보았습니다.

    좋은 웹페이지 즐겨찾기