class SimpleGradebook:
def __init__(self):
self._grades = {}
def add_student(self, name):
self._grades[name] = []
def report_grade(self, name, score):
self._grades[name].append(score)
def average_grade(self, name):
grades = self._grades[name]
if not len(grades):
raise ValueError("입력된 성적이 없습니다")
return sum(grades) / len(grades)
class
is simple (나는 아직 객체지향에 대한 이해가 부족..)book = SimpleGradebook()
book.add_student('Issac Newton')
book.report_grade('Issac Newton', 90)
book.report_grade('Issac Newton', 95)
book.report_grade('Issac Newton', 85)
>>> print(book.average_grade('Issac Newton'))
90.0
key
와 value
로 집어넣은 것이다.그러나 필자에 따르면, 딕셔너리는 쓰기 쉬워서 overextending하다가 코드를 취약하게 만들 수 있다. 가령, SimpleGradbook
클래스를 확장하여 사용하지 않고 과목별로 저장한 다음에 dict
으로 매핑할 수 있다. 즉 딕셔너리 안에 딕셔너리가 들어가는 형태
class BySubjectGradebook:
def __init__(self): # outer dict
self._grades = {}
def add_student(self, name):
self._grades[name] = defaultdict # inner dict
def report_grade(self, name, subject, grade):
by_subject = self._grades[name]
grade_list = by_subject.setdefault(subject, [])
grade_list.append(grade)
def average_grade(self, name):
by_subject = self._grades[name]
total, count = 0, 0
for grades in by_subject.values():
total += sum(grades)
count += len(grades)
return total / count
위에까지는 나름 다룰만 하다고 필자는 주장한다
클래스를 활용하는 것도 simple하다
book = BySubjectGradebook()
book.add_student('Albert Einstein')
book.report_grade('Albert Einstein', 'Math', 75)
book.report_grade('Albert Einstein', 'Math', 65)
book.report_grade('Albert Einstein', 'Gym', 90)
book.report_grade('Albert Einstein', 'Gym', 95)
print(book.average_grade('Albert Einstein'))
>>> 81.25
파이썬의 내장된 dict나 tuple을 활용하면 레이어를 추가하여 계속 진행하기 쉽다. 그러나 둘 이상이 될 때는 하지 않는 것이 좋다. (다른 사람이 보기 좋지 않고, 유지와 관리가 어렵다)
grades = []
grades.append((95, 0.45))
grades.append((85, 0.55))
total = sum(score * weight for score, weight in grades)
total_weight = sum(weight for _, weight in grades)
average_grade = total / total_weight
그런데 위의 코드의 문제는 일반 튜플은 위치에 의존한다.
따라서 아래와 같은 코드를 제시하였다
grades = []
grades.append((95, 0.45, 'Great job'))
grades.append((85, 0.55, 'Better next time'))
total = sum(score * weight for score, weight, _ in grades)
total_weight = sum(weight for _, weight, _ in grades)
average_grade = total / total_weight
이런 패턴의 튜플은 deepening layers of dictionaries와 유사하다. (딕셔너리의 계층을 깊게 두는 방식)
만약 튜플의 아이템이 2개를 넘어가면 다른 방법을 고려하는디 이때 collections
모듈의 namedtuple
을 활용하면 해결할 수 있다.
from collections import namedtuple
Grade = namedtuple('Grade', ('score', 'weight'))
이 fields는 named attribute
로 접근할 수 있다. (문자열 이름을 속성으로 접근할 수 있다.)
namedtuple
에 관한 한계를 일부 정리해두었다.파이썬의 내장 api의 상당수는 함수를 넘겨서 동작을 사용자화하는 기능이 있다. hook를 이용해서 작성한 코드를 실행 중에 호출한다고 한다.
가령, list의 sort 메소드에는 key라는 인자를 받을 수 있다.
names = ['Socrates', 'Archimedes', 'Plato', 'Aristotle']
names.sort(key=len)
print(names)
이 파트는 이해가 잘 안되어서 ㅠㅠ 공란으로 잠시 두고 스터디 이후에 제대로 채우도록 하겠습니다
필자는 아래와 같은 예제코드를 제시해 주었다.
class FrequencyList(list):
def __init__(self, members):
super().__init__(members)
def frequency(self):
counts = {}
for item in self:
counts[item] = counts.get(item, 0) + 1
return counts