@property, @setter, @deleter

1. 소개

  • 클래스의 메서드를 속성(attribute) 처럼 다룰 수 있게 해주는 데코레이터
  • 속성처럼 obj.name 처럼 호출하지만, 실제로는 내부 메서드가 실행되어 속성을 조회하는 방식
  • 속성을 메서드로 다루기 때문에, 속성 조회, 검증, 계산 등의 통제를 자동으로 할 수 있게 해준다.
데코레이터 기능
@property getter 를 만드는 데코레이터로, 메서드를 읽기 전용 속성처럼 만들어준다.
속성을 읽을 때 사용.
@setter 메서드를 속성에 값을 대입하는 setter로 만들어준다. 값의 검증 로직을 추가할 수 있다.
속성을 대입할 때 사용.
@deleter 메서드를 통해 속성을 제거할 때 사용된다.

2. 사용법

(1) @property

1
2
3
4
5
6
7
8
9
10
class User:
    def __init__(self, name:str):
        self._name = name

    @property
    def name(self):
        return self._name

u = User("소크라테스")
print(u.name)
1
소크라테스

(2) @setter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class User:
    def __init__(self, name:str|None = None):
        self._name = name

    @property
    def name(self):
        return self._name
    
    @name.setter
    def name(self, name):
        self._name = name

u = User()
u.name = "소크라테스"
print(u.name)
1
소크라테스

(3) @deleter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class User:
    def __init__(self, name:str):
        self._name = name

    @property
    def name(self):
        return self._name

    @name.deleter
    def name(self):
        del self._name

u = User("소크라테스")
del u.name
print(u.name)
1
AttributeError: 'User' object has no attribute '_name'

2. 사용하는 이유

(1) 속성값을 읽을 때 변환 로직을 넣기 위해

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Temperature:
    def __init__(self, celsius):
        self._celsius = celsius

    @property
    def celsius(self):
        return self._celsius

    @property
    def fahrenheit(self):
        return self._celsius * 9 / 5 + 32

t = Temperature(30)
print("celsius : ", t.celsius)
print("fahrenheit : ", t.fahrenheit)
1
2
celsius :  30
fahrenheit :  86.0

(2) 속성값을 넣을 때 값을 검증하기 위해

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class User:
    def __init__(self, email:str|None = None):
        self._email = email

    @property
    def email(self):
        return self._email

    @email.setter
    def email(self, value):
        if "@" not in value:
            raise ValueError("올바른 이메일 형식이 아닙니다.")
        self._email = value

u = User()
u.email = "abcdefg"
1
올바른 이메일 형식이 아닙니다.

(3) 외부에서의 사용 방식은 유지하고, 내부 구현을 바꿀 때

1
2
3
4
5
6
7
8
9
10
11
12
13
class Dollar:
    def __init__(self, dollar):
        self._dollar = dollar

    @property
    def korean_won(self):
        exchange_rate = 1400
        return self._dollar * exchange_rate

d = Dollar(1)
print(d.korean_won)

# >> 1400
1
2
3
4
5
6
7
8
9
10
11
12
13
class Dollar:
    def __init__(self, dollar):
        self._dollar = dollar

    @property
    def korean_won(self):
        exchange_rate = 1500
        return self._dollar * exchange_rate

d = Dollar(1)
print(d.korean_won)

# >> 1500

(4) 기능을 가지면서, 호출할 때에는 일반 속성처럼 호출

  • 값의 변환 기능을 가지는 일반 메서드를 만들 경우
1
2
3
4
5
6
7
8
9
class Temperature:
    def __init__(self, celsius):
        self._celsius = celsius

    def fahrenheit(self):
        return self._celsius * 9 / 5 + 32

t = Temperature(30)
t.fahrenheit()
  • @property 를 사용하는 경우
1
2
3
4
5
6
7
8
9
10
class Temperature:
    def __init__(self, celsius):
        self._celsius = celsius

    @property
    def fahrenheit(self):
        return self._celsius * 9 / 5 + 32

t = Temperature(30)
t.fahrenheit

3. 결론

  • @property 를 사용하는 것은, “이 값은 객체의 속성이다”라는 의미를 더 자연스럽게 표현함
  • 이처럼 상태, 성질(속성)처럼 보이고 싶은 경우 property 데코레이터를 사용하고
  • 행동 중심, 특정 작업처럼 보이고 싶은 경우엔 일반 메서드를 사용하면 된다.

Comments