동적(dynamic)
#예시
#학생들의 점수를 기록할 때, 학생의 이름을 모르는 경우
"""
학생별로 미리 정의된 애트리뷰트 사용대신 딕셔너리에 이름을 저장하는 클래스 정의
"""
class SimpleGradebook:
def __init__(self):
self._grades = {}
def add_student(self, name):
self._grades[names] = []
def report_grade(self, name, score):
self._grades[name].append(score)
def average_grade(self, name):
grades = self._grades[name]
return sum(grades) / len(grades)
book = SimpleGradebook()
book.add_student('아이작 뉴턴')
book.report_grade('아이작 뉴턴', 90)
book.report_grade('아이작 뉴턴', 95)
book.report_grade('아이작 뉴턴', 85)
print(book.average_grade('아이작 뉴턴')) #90.0
위의 코드는 너무 확장을 많이 해서 깨지기 쉬운 코드
코드를 변경해도 가독성이 떨어질 확률이 높다.
내포 단계가 두 단계 이상일 경우 딕셔너리, 리스트, 튜플 계층 추가하지 말 것
클래스로 기능 분리
캡슐화 해주는 잘 정의딘 인터페이스 제공
잘 정의된 추상화 계층 가능
의존관게 트리의 맨 밑바닥: 내포된 딕셔너리, 튜플, 리스트
원소 세 개 이상인 튜플을 사용해야한다면, 다른 접근하기
namedtuple
클래스의 인스턴스 만들 시 위치 기반 인자와 키워드 인자 사용
필드에 접근 시, 애트리뷰트 이름 쓰기 가능
요구사항이 바뀌어도 클래스로 변경이 쉽다.
즉, 가변성을 지원한다.
from collections import namedtuple
Grade = namedtuple('Grade', ('score','weight')
디폴트 인자 값을 지정할 수 없다.
선택적 property가 많은 데이터 사용이 어려움
API경우 실제 클래스 변경은 어렵다.
#```
점수를 포함하는 단일 과목 표현하는 클래스 작성
class Subject:
def init(self):
self._grades = []
def report_grade(self, score, weight):
self._grades.append(Grade(score, weight)
def average_grade(self):
total, total_weight = 0.0
for grade in self._grades:
total += grade.score * grade.weight
total_weight += grade.weight
return total / total_weight
#수강하는 과목을 표현하는 클래스 작성
class Student:
def init(self):
self._subjects = defaultdict(Subject)
def get_subject(self, name):
return self._subjects[name]
def average_grade(self):
total, count = 0,0
for subject in self._subjects.values():
total += subject.average_grade()
count += 1
return total / count
#모든 학생을 저장하는 컨테이너를 만들어서 이름을 사용해서 동적으로 학생 저장
class Gradebook:
def init(self):
self._students = defaultdict(Student)
def get_student(self, name):
return self._students[name]
#API를 사용중인 코드를 새로운 객체 계층을 사용하는 코드로 쉽게 마이크레이션 가능
book = Gradebook()
albert = book.get_student('알버트 아인슈타인')
math = albert.get_subject("수학")
math.report_grade(75,0.05)
math.report_grade(65,0.15)
math.report_grade(70,0.80)
gym = albert.get_subject('체육')
gym.report_grade(100,0,40)
gym.report_grade(85,0,60)
print(albert.average_grade()) #80.25