-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbetter_way_46.py
59 lines (46 loc) · 2.25 KB
/
better_way_46.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
""" `__get__`과 `__set__`을 구현하는 일을 디스크립터 프로토콜을 구현하는 일이라고 한다.
디스크립터 프로토콜은 파이썬에서 애트리뷰트 접근을 해석하는 방법을 정의한다.
@property (getter), setter이 점점 많아지는 것 같을 때 선택을 고민해보자.
디스크립터 프로토콜을 이용하면 비슷한 성질을 가진 애트리뷰트들에 대해서
동일한 getter, setter 로직을 하나의 메서드 내부에 모아 표현할 수 있기 때문이다.
"""
from weakref import WeakKeyDictionary
class Grade:
def __init__(self) -> None:
self._values = WeakKeyDictionary()
# 여기서 WeakKeyDictionary를 사용하는 이유는
# `self._values`에서 `Exam` 클래스 객체를 참조하고 있어
# 발생하는 메모리 누수를 막기 위함이다.
def __get__(self, instance, instance_type):
# 파이썬에서는 기본적으로 객체의 멤버 변수를 조회하기 위해
# `a.b` 와 같은 구문을 사용할 때
# 객체 exam 의 애트리뷰트를 먼저 뒤진 다음, 발견하지 못하면
# 클래스 Exam 의 클래스 애트리뷰트를 뒤진다.
if instance is None:
return self
return self._values.get(instance, 0)
def __set__(self, instance, value):
if not (0 <= value <= 100):
raise ValueError(
'점수는 0과 100 사이입니다.'
)
self._values[instance] = value
class Exam:
math_grade = Grade()
writing_grade = Grade()
science_grade = Grade()
if __name__ == '__main__':
first_exam = Exam()
second_exam = Exam()
# first_exam.writing_grade = 82 코드는
# 다음과 같이 다시 작성해볼 수 있다.
# Exam.__dict__['writing_grade'].__set__(exam, 82)
first_exam.writing_grade = 82
# Exam.__dict__['writing_grade'].__set__(exam, 82)
second_exam.writing_grade = 75
# print(first_exam.writing_grade) 코드는
# 다음과 같이 다시 작성해볼 수 있다.
# Exam.__dict__['writing_grade'].__get__(exam, Exam)
print(f'{first_exam.writing_grade} 맞음')
# Exam.__dict__['writing_grade'].__get__(exam, Exam)
print(f'{second_exam.writing_grade} 맞음')