@property
파이썬에 _(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를 쓰는 이유를 정리하자면 아래와 같습니다.
- private 변수에 대한 가변성에 제한을 주고 싶어서
- getter와 setter를 사용하지 않고 좀 더 간단하게 데이터에 접근하고 싶을때
- 하위 호환성 (setter에 age < 0이라는 컨디션을 줄 수 있음)