python

@property

sklass 2021. 8. 26. 23:16

파이썬에 _(underscore)를 변수명 앞에 붙히면, private 역할을 한다는 의미지만, 파이썬의 특성상 문법적으로 private을 강제할 수 없기 때문에 _를 붙혔다 하더라도, self._age 이런식으로 접근 가능합니다.

 

하지만 OOP를 하고자 할때 클래스 안의 private 변수를 외부에서 변경할 수 없게끔 Encapsulation을 보장하고 싶을때가 있습니다. 이럴때 @property를 쓰면 유용합니다.

 

property()

우선 파이썬 내장함수인 property()를 살펴보겠습니다.

property()를 사용하면 마치 필드명을 사용하는 것처럼 깔끔하게 getter/setter 메서드가 호출되게 할 수 있습니다.

class Person:
    def __init__(self, first_name, last_name, age):
        self.first_name = first_name
        self.last_name = last_name
        self._age = age

    def get_age(self):
        return self._age

    def set_age(self, age):
        if age < 0:
            raise ValueError("Invalid age")
        self._age = age

    age = property(get_age, set_age)

property()의 첫번째 인자로 getter, 두번째 인자로 setter 메서드를 넘겨주면 아래와 같이 age라는 필드명을 이용해서 데이터에 접근 가능해집니다.

person = Person("John", "Doe", 20)
print(person.age)
>> 20

person.age = -1
>> ValueError: Invalid age

person.age = person.age + 1
print(person.age)
>> 21

위와 같이 필드명만을 이용해서 값을가져오고 값을 변경해주는것 같지만 내부적으로는 property()를 이용해서 설정한 getter와 setter 메서드가 호출되고 있는 상황입니다.

 

@property

파이썬 내장 데코레이터인 @property를 사용하면 조금더 편리하게 getter와 setter를 설정할 수 있습니다.

class Person:
    def __init__(self, first_name, last_name, age):
        self.first_name = first_name
        self.last_name = last_name
        self._age = age

    @property
    def age(self):
        return self._age

    @age.setter
    def age(self, age):
        if age < 0:
            raise ValueError("Invalid age")
        self._age = age

 

Immutable Private Variable

만약 파이썬 클래스에서 값을 변경 불가능한 private variable을 만들고자 한다면 아래와 같이 setter를 설정하지 않으면 됩니다.

class Person:
    def __init__(self, first_name, last_name, age):
        self.first_name = first_name
        self.last_name = last_name
        self._age = age

    @property
    def age(self):
        return self._age

 

이렇게 되면 Person.age의 값을 변경하려 할때 아래와 같은 Attribute Error를 볼 수 있습니다.

person = Person("John", "Doe", 20)
print(person.age)
>> 20

person.age = 30
>> AttributeError: can't set attribute

 

마치며..

property()와 @property를 쓰는 이유를 정리하자면 아래와 같습니다.

  1. private 변수에 대한 가변성에 제한을 주고 싶어서
  2. getter와 setter를 사용하지 않고 좀 더 간단하게 데이터에 접근하고 싶을때
  3. 하위 호환성 (setter에 age < 0이라는 컨디션을 줄 수 있음)