Python @property 실습 중심 가이드
이 글은 Python의 @property를 사용해 “메서드를 속성처럼 사용하는 방법”을 실습 위주로 설명하는 가이드입니다.
1. @property 한 줄 정의
@property는 “메서드를 속성처럼 보이게 만들어 주는 문법”입니다.
예를 들어 다음과 같은 코드가 가능해집니다.
class Person:
@property
def name(self):
return self._name
내부적으로는 name()이라는 메서드이지만,
외부에서는 p.name처럼 괄호 없이 속성 접근 문법으로 사용할 수 있습니다.
2. 전통적인 get/set 방식 vs @property
2-1. get/set 메서드를 사용하는 방식
class Person:
def __init__(self, name):
self._name = name
def get_name(self):
return self._name
def set_name(self, value):
self._name = value
p = Person("Alice")
p.get_name()
p.set_name("Bob")
2-2. @property를 사용하는 방식
class Person:
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self, value):
self._name = value
p = Person("Alice")
print(p.name) # getter
p.name = "Bob" # setter 호출
기능적으로는 비슷하지만, p.name, p.name = ... 처럼
훨씬 자연스러운 문법으로 사용할 수 있습니다.
3. 기본 패턴 – getter / setter / deleter
3-1. 읽기 전용 프로퍼티 (getter만 있는 경우)
class Person:
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
p = Person("Alice")
print(p.name)
# p.name = "Bob" # AttributeError: can't set attribute
setter를 정의하지 않으면 해당 프로퍼티는 읽기 전용이 됩니다.
3-2. setter 추가
class Person:
def __init__(self, name):
self._name = None
self.name = name # 아래 setter를 통해 값 설정
@property
def name(self):
return self._name
@name.setter
def name(self, value):
if not value:
raise ValueError("이름은 비어 있을 수 없습니다.")
self._name = value
p = Person("Alice")
p.name = "Bob"
p.name = "" # ValueError 발생
@name.setter에서 사용하는 메서드 이름은
반드시 프로퍼티 이름(name)과 같아야 합니다.
3-3. deleter (참고용)
class Person:
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
@name.deleter
def name(self):
print("이름을 삭제합니다.")
del self._name
p = Person("Alice")
del p.name
실무에서 자주 쓰이진 않지만, 삭제 시에도 커스텀 로직을 넣을 수 있다는 정도만 알아두면 충분합니다.
4. @property가 유용한 상황들
4-1. 내부 구현을 숨기고 외부 API는 유지하고 싶을 때
처음에는 넓이(면적)를 직접 계산하고 있었다고 가정해 봅시다.
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
rect = Rectangle(3, 4)
area = rect.width * rect.height
이후에 rect.area로 넓이를 표현하고 싶어졌습니다.
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
@property
def area(self):
return self.width * self.height
rect = Rectangle(3, 4)
print(rect.area)
넓이를 계산하는 로직은 메서드 안으로 들어갔지만, 외부에서는 여전히 속성처럼 사용할 수 있어서 코드 사용처를 크게 수정하지 않고도 내부 구현을 바꿀 수 있습니다.
4-2. 값 설정 시 유효성 검사가 필요할 때
class Person:
def __init__(self, name, age):
self.name = name
self._age = None
self.age = age
@property
def age(self):
return self._age
@age.setter
def age(self, value):
if value < 0:
raise ValueError("나이는 음수가 될 수 없습니다.")
self._age = value
p = Person("Alice", 30)
p.age = -1 # ValueError
외부에서는 p.age = 값처럼 단순하게 보이지만,
내부적으로는 언제나 유효성 검사가 거쳐지도록 만들 수 있습니다.
4-3. 계산된 속성 (Computed Property)
class Product:
def __init__(self, price, quantity):
self.price = price
self.quantity = quantity
@property
def total(self):
return self.price * self.quantity
item = Product(1000, 3)
print(item.total) # 3000
total은 실제로는 저장된 값이 아니라,
다른 속성(price, quantity)을 이용해 매번 계산하는
“계산된 속성”입니다.
5. property() 함수 형태
@property는 문법 설탕(syntax sugar)이고, 원형은 property() 함수입니다.
class Person:
def __init__(self, name):
self._name = name
def get_name(self):
return self._name
def set_name(self, value):
self._name = value
name = property(get_name, set_name)
p = Person("Alice")
print(p.name) # get_name() 호출
p.name = "Bob" # set_name() 호출
현재는 가독성이 좋은 @property / @name.setter 데코레이터 형태를 사용하는 것이 일반적입니다.
6. @property 사용 시 주의할 점
6-1. 너무 무거운 작업을 넣지 않기
obj.data 같은 속성 접근이
내부적으로는 DB 조회나 네트워크 호출 같은 무거운 작업을 수행하면,
코드를 읽는 사람이 예상하기 어렵습니다.
무거운 작업은
get_data()와 같은 메서드로 만드는 편이 더 명확할 때가 많습니다.
6-2. 강한 사이드 이펙트는 신중하게
obj.value를 읽는 것만으로 파일을 생성한다거나,
내부 상태를 크게 변경하는 등의 사이드 이펙트는 가능한 한 피하는 것이 좋습니다.
7. 한 줄 요약
- @property는 “메서드를 속성처럼 보이게 해주는 도구”이다.
- getter만 있으면 읽기 전용, setter를 추가하면 쓰기 가능하다.
- 내부 구현을 바꾸더라도 외부 API(
obj.x)를 유지하고 싶을 때 특히 유용하다. - 유효성 검사, 계산된 속성 등에서 많이 쓰이며, 너무 무거운 작업이나 예상 밖의 사이드 이펙트는 피하는 것이 좋다.
8. 연습 문제
연습 1 – BankAccount.balance
BankAccount 클래스를 만들고 다음을 구현해 보세요.
- 내부 잔액은
_balance에 저장 - 외부에는
balance프로퍼티로 노출 balance를 설정할 때 0 미만으로 내려가면ValueError발생
연습 2 – Vector2D.length
Vector2D 클래스를 만들고:
x,y속성length프로퍼티 –sqrt(x*x + y*y)를 반환length에는 setter를 두지 않고 읽기 전용으로만 사용
이런 연습을 통해, @property를 “언제, 어떤 패턴에 쓰면 좋은지” 감이 훨씬 잘 잡힐 것입니다.
'프로그래밍 > Python' 카테고리의 다른 글
| [Python] lru_cache는 언제 사용해? (0) | 2025.12.15 |
|---|---|
| [Python] classmethod는 언제 사용해? (0) | 2025.12.15 |
| [Python] staticmethod는 언제 사용해? (0) | 2025.12.15 |
| [Python] decorator에서 wrapper 자세히 보기 (0) | 2025.12.15 |
| [Python] Decorator 입문 훑기 (1) | 2025.12.15 |