Python @property 데코레이터 마스터하기: 깔끔하고 하위 호환 가능한 게터/세터
Python @property 데코레이터 마스터하기
Python 내장 @property 데코레이터로 간결하고 유지보수 쉬운 게터/세터 작성하면서 API 하위 호환성 유지하는 법 알아보기.
Python @property 데코레이터는 속성 접근 캡슐화 강력한 도구. 호출자 코드 변경 없이 속성 읽기/쓰기 시 커스텀 로직 실행 가능. 다음 섹션에서 온도 변환 실전 예제로 제약 조건 강제와 @property가 관용적 해법인 이유 설명.
게터/세터 없는 클래스
섭씨 온도 저장하고 화씨 변환 가능한 간단 클래스 필요하다고 가정:
class Celsius:
def __init__(self, temperature=0):
self.temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
사용법 직관적:
# 새 객체 생성
human = Celsius()
# 온도 설정
human.temperature = 37
# 온도 읽기
print(human.temperature)
# 화씨 변환
print(human.to_fahrenheit())
출력
37 98.60000000000001
부동소수점 결과는 십진수 이진 표현 탓에 예상됨. human.__dict__ 보면 Python이 값을 일반 딕셔너리 항목에 저장:
>>> human.__dict__
{'temperature': 37}
게터/세터로 제약 조건 추가
현실 객체는 검증 필요. 예: 온도 절대 영도(-273.15 °C) 이하 불가능. 직관적 방법은 속성 숨기고 명시적 게터/세터 노출:
class Celsius:
def __init__(self, temperature=0):
self.set_temperature(temperature)
def to_fahrenheit(self):
return (self.get_temperature() * 1.8) + 32
# 게터
def get_temperature(self):
return self._temperature
# 세터
def set_temperature(self, value):
if value < -273.15:
raise ValueError("Temperature below -273.15 is not possible.")
self._temperature = value
이제 클래스가 하한 강제하지만 기존 obj.temperature 접근 코드는 obj.get_temperature(), obj.set_temperature(val) 호출로 수정해야. 대규모 코드베이스엔 큰 리팩터링.
게다 Python "비공개" 변수는 명명 관례일 뿐—_temperature 직접 접근 가능해 캡슐화 깨짐. 여기서 @property 빛남.
property 클래스 사용
Python은 게터/세터 함수를 속성 이름에 연결하는 property 클래스 제공:
class Celsius:
def __init__(self, temperature=0):
self.temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
# 게터
def get_temperature(self):
print("Getting value...")
return self._temperature
# 세터
def set_temperature(self, value):
print("Setting value...")
if value < -273.15:
raise ValueError("Temperature below -273.15 is not possible")
self._temperature = value
# 프로퍼티로 노출
temperature = property(get_temperature, set_temperature)
이 설정으로 다음 코드는 원래 단순 클래스처럼 동작하지만 내부적으론 검증 수행:
human = Celsius(37)
print(human.temperature) # 게터 트리거
print(human.to_fahrenheit()) # 내부적으로 게터 사용
human.temperature = -300 # 세터 트리거, ValueError 발생
출력
Setting value... Getting value... 37 Getting value... 98.60000000000001 Setting value... Traceback (most recent call last): ... ValueError: Temperature below -273 is not possible
temperature 접근 코드 변경 없이 내부 구현만 검증 추가됨.
팁: 실제 데이터는 _temperature에, temperature는 편리하고 안전한 인터페이스일 뿐.
@property 데코레이터
property 클래스도 작동하지만 Python 데코레이터 문법이 더 깔끔하고 읽기 쉬운 동일 결과 제공. 데코레이터가 자동으로 프로퍼티 객체 생성해 게터/세터를 속성 이름에 부착.
class Celsius:
def __init__(self, temperature=0):
self.temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
@property
def temperature(self):
print("Getting value...")
return self._temperature
@temperature.setter
def temperature(self, value):
print("Setting value...")
if value < -273.15:
raise ValueError("Temperature below -273 is not possible")
self._temperature = value
사용법 동일:
human = Celsius(37)
print(human.temperature)
print(human.to_fahrenheit())
# 유효하지 않은 온도 설정 시도
try:
Celsius(-300)
except ValueError as e:
print(e)
출력
Setting value... Getting value... 37 Getting value... 98.60000000000001 Setting value... Traceback (most recent call last): ... ValueError: Temperature below -273 is not possible
@property 사용으로 네임스페이스 깔끔, 별도 게터/세터 메서드 이름 불필요, 대부분 Python 개발자 권장 패턴.