질문의 역사:
클래식 OOP에서 캡슐화는 개인 필드와 getter/setter를 통해 구현되지만, 이는 복잡하고 "파이썬스럽지" 않습니다. 파이썬 2.2 버전부터 @property 데코레이터가 도입되어 getter와 setter 메서드에 일반 속성처럼 접근할 수 있어, 우아한 문법으로 효율적인 캡슐화를 구현하게 되었습니다.
문제:
데코레이터 없이 property를 사용하려면 접근 및 값을 설정하기 위해 메서드를 명시적으로 정의해야 합니다(예: get_x() 및 set_x(val)), 이로 인해 코드는 덜 읽기 쉬워지며 클래스 사용자는 내부 데이터에 직접 접근할 위험이 있습니다. 내부 저장 방식이나 값 계산 로직을 변경할 때 문제가 발생합니다.
해결:
@property 데코레이터를 사용하면 하나의 문법으로 getter, setter 및 deleter를 정의할 수 있습니다. 이는 간결하고 편리하며 구현 세부 정보를 캡슐화하고 속성을 계산하는 방식을 변경하더라도 클래스의 인터페이스가 손상되지 않도록 합니다.
코드 예시:
class Temperature: def __init__(self, celsius): self._celsius = celsius @property def celsius(self): return self._celsius @celsius.setter def celsius(self, value): if value < -273.15: raise ValueError("-273.15°C 이하의 온도는 불가능합니다!") self._celsius = value
주요 특징:
@property 데코레이터는 메서드에 일반 속성처럼 접근할 수 있게 해줍니다.읽기 전용 속성을 만들 수 있지만, 쓰기/삭제는 할 수 없나요?
네, @property 데코레이터가 있는 메서드만 정의하고 setter와 deleter를 정의하지 않으면, 해당 속성은 읽기 전용으로 제공됩니다.
class Sample: @property def value(self): return 42
property 이름이 개인 속성과 중복되면 어떻게 되나요?
보통 property는 개인 속성에 대한 "레이어"로 사용되며, 해당 이름은 언더스코어로 시작합니다(예: _x). 이러한 중복은 피해야 하며, 그렇지 않으면 재귀 호출이 발생할 수 있습니다:
class Bad: @property def x(self): return self.x # 무한 재귀
클래스에만 property를 지정할 수 있나요?
아니요, 표준 @property는 클래스의 인스턴스와 함께 작동합니다. 클래스 속성을 만들려면 외부 패턴이나 특별한 라이브러리를 사용해야 하며(@classmethod와 함께 property는 직접 작동하지 않습니다).
개발자가 클래스 필드(self.celsius)에 직접 접근하여 property를 사용하지 않습니다. 나중에 검증 로직이 추가되지만, 클래스 사용자들은 여전히 개인 속성을 직접 수정하여 검증을 우회할 수 있습니다.
장점:
복잡한 로직이 없을 때 쉽고 빠르게 작업할 수 있습니다.
단점:
캡슐화가 훼손되어 객체의 잘못된 상태를 얻기 쉬워지고 혼란이 발생할 수 있습니다.
property를 사용하고 내부 속성을 _celsius를 통해 숨깁니다. 검증, 캐싱 및 로직이 property 내부에 중앙 집중화됩니다.
장점:
코드가 보호되고 인터페이스가 안정적입니다 — 속성 구현을 변경하더라도 클래스 사용자에게 영향이 없습니다.
단점:
크고 복잡한 객체의 경우 property를 지나치게 사용하면 디버깅의 복잡성이 증가할 수 있습니다.