BATTER WAY 29. 게터와 세터 메서드 대신에, 일반 속성을 사용하자.
- 다른 언어를 사용하다가, 파이썬으로 넘어온 프로그래머들은 자연스럽게 클래스에 게터(
getter
)와 세터(setter
) 메서드를 명시적으로 구현하려고 한다.
class OldResistor(object):
def __init__(self, ohms):
self._ohms = ohms
def get_ohms(self):
return self._ohms
def set_ohms(self, ohms):
self._ohms = ohms
r0 = OldResistor(50e3)
print(f'Before: {r0.get_ohms()}') # Before: 50000.0
r0.set_ohms(10e3)
print(f'Before: {r0.get_ohms()}')')') # After: 10000.0
r0.set_ohms(r0.get_ohms() + 5e3)
- 사용하는 법은 간단하지만, 파이썬 스럽지 않은 코딩 방법이다.
- 겟터와 셋터는 값을 증가시키고 그 값을 바로 반영하기 불편하다.
- 파이썬은 명시적인 게터와 세터를 구현할 일이 거의 없다. 대신 공개 속성부터 구현하기 시작해야 한다.
class Register(object):
def __init__(self, ohms):
self.ohms = ohms
self.voltage = 0
self.current = 0
r1 = Register(50e3)
r1.ohms = 10e3
r1.ohms += 5e3
-
만약 속성을 설정할 때, 특별한 동작이 일어나야 한다면
@property
데코레이터와 이에 대응하는setter
속성을 사용하는 방법으로 바꿀 수 있다. -
여기서는
Registor
의 새 서브 클래스를 정의하여,voltage
프로퍼티를 할당하면,current
값이 바뀌도록 해본다. -
제대로 동작하려면, 세터와 게터의 이름이 의도한 프로퍼티의 이름과 같아야한다.
class VoltageResistance(Register):
def __init__(self, ohms):
super().__init__(ohms)
self._voltage = 0
@property
def voltage(self):
return self._voltage
@voltage.setter
def voltage(self, voltage):
self._voltage = voltage
self.current = self._voltage / self.ohms
r2 = VoltageResistance(1e3)
print(f'Before: {r2.current}') # 0
r2.voltage = 10
print(f'After: {r2.current}')')') # 0.01
- 프로퍼티에
setter
를 설정하면, 클래스에 전달된 값들의 타입을 체크하고 값을 검증할 수 있다.
class BoundedResistence(Register):
def __init__(self, ohms):
super().__init__(ohms)
@property
def ohms(self):
return self._ohms
@ohms.setter
def ohms(self, ohms):
if ohms <= 0:
raise ValueError(f"{ohms} ohms must be > 0")
r3 = BoundedResistence(1e3)
r3.ohms = 0
- 프로퍼티에
setter
를 설정하면, 클래스에 전달된 값들의 타입을 체크하고 값을 검증할 수 있다. - 다음은 모든 저항값이 0옴보다 큼을 보장하는 클래스를 정의한 것이다.
- 만약
ohms
속성값이 0이거나, 0보다 작으면 예외가 발생하게 된다.
class FixedResistence(Register):
def __init__(self, ohms):
super().__init__(ohms)
@property
def ohms(self):
return self._ohms
@ohms.setter
def ohms(self, ohms):
if hasattr(self, '_ohms'):
raise ValueError("Can't set attribute")
self._ohms = ohms
- 부모 클래스의 속성을 불변(Immutable)로 만드는데도 @property를 사용할 수 있다.
핵심 정리
-
간단한 공개 속성을 사용하여 새 클래스 인터페이스를 정의하고, 세터와 게터 메서드는 사용하지 말자.
-
객체의 속성에 접근할 때 특별한 동작을 정의하려면
@property
를 사용하자. -
@property
메서드에서 최소 놀람 규칙을 따르고 이상한 부작용을 피하자. -
@property
메서드가 빠르게 동작하도록 만들자. 느리거나 복잡한 작업은 일반 메서드로 하자.