객체지향에서의 Attribute, Python의 @property와 @속성.setter


객체지향 프로그래밍에서는 객체의 속성 (attribute)을 행위 (method)를 통하여 객체를 나타냅니다.
자동차를 객체로 생각한다면 한 자동차에서 속성중 하나인 기름의 양을 oil_amount 변수로 또 자동차의 행위중 하나인 앞으로 나아간다를 go_forward라는 행위 (method)로 표현하여 자동차를 “객체화” 할 수 있습니다.
자동차라는 개념을 우리의 프로그래밍안에 나타내고자 자동차에서 우리가 필요한 속성과 행위만 끄집어내어 추상화 한 것입니다.
파이썬의 @property는 이 중 속성에 대해 더 깊이 들여다볼 주제입니다.

예를 들어

1
2
3
4
5
6
7
8
class Car:
def __init__(self, initial_oil_amount):
self.__oil_amount = initial_oil_amount
self.__coordinate = 0

def go_forward(self):
self.__oil_amount -= 1
self.__coordinate += 1

라는 객체를 표현했다고 생각해봅시다.

우선 Car라는 객체의 속성값들이 표현되어있는 _init_안을 보면 self로 하여 표현한다는 것을 알겠는데 왜 \(double underscore, dunder, 던더, 더블 밑줄)을 앞에 붙여서 선언했을까요?

저것은 일종의 약속입니다. 이 속성값은 이 객체의 밖에서 함부로 접근할 수 없다라고 “파이썬”에서 사용하는 약속입니다. 저 약속과 관계없이 얼마든지 바꿀 수는 있습니다. 하지만 그러면 지금부터 알아볼 @property의 의미가 무색해지겠죠.

왜 이런식의 약속이 필요한지에 대한 질문은 여기서는 생략하도록 하겠습니다.

자 그렇다면 self.__oil_amount를 바꾸고 싶다면, 예를 들어 차에 기름을 충전하는 객체가 한 Car객체에 기름을 충전하여 기름의 양 속성이 외부에서 더 해져야 한다면 어떻게 해야할 까? (물론 self.__oil_amount를 직접 바꾸지 않는다는 약속하에)

이때 @property가 들어옵니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Car:

def __init__(self, initial_oil_amount):
self.__oil_amount = initial_oil_amount
self.__coordinate = 0

def go_forward(self):
self.__oil_amount -= 1
self.__coordinate += 1

@property
def oil_amount(self):
return self.__oil_amount

@oil_amount.setter
def oil_amount(self, new_oil_amount):

self.__oil_amount += new_oil_amount

이렇게 정의하게 되면

1
2
3
4
5
6
7
8
9
10
car = Car(5)
car.oil_amount()
>>> 5

car.go_forward()
car.oil_amount()
>>> 4

car.oil_amount(3)
>>> 7

위 처럼 car.oil_amount()는 self.__oil_amount의 getter 처럼,
car.oil_amount(variable)은 self.__oil_amount의 setter처럼 작동하게 됩니다.