effective python 读书笔记-第22条: 尽量用辅助类来维护程序的状态,而不要用字典

第22条: 尽量用辅助类来维护程序的状态,而不要用字典

带着问题学习

  1. 如何使用字段维护程序的状态?
  2. 如何使用辅助类为辅程序的状态?
  3. 有没有更好的方式?

总结

  • 1.1 使用字典维护程序的状态(简单示例)
需求:
记录学生的名字,记录学生对应的科目(假设一个科目)的多次成绩


代码实现:
class SimpleGradebook(object):
    def __init__(self):
        self.grades = {}

    def add_student(self, name):
        if name in self.grades:
            raise ValueError('no named {}'.format(name))
        self.grades[name] = []

    def report_grade(self, name, score):
        if name not in self.grades:
            raise ValueError('no named {}'.format(name))
        self.grades[name].append(score)

    def average_grade(self, name):
        grades = self.grades[name]
        return sum(grades) / len(grades)


book = SimpleGradebook()
book.add_student('xiaoming')
book.report_grade('xiaoming', 90)
book.report_grade('xiaoming', 80)
print(book.average_grade('xiaoming'))
# 85

book.add_student('liming')
book.report_grade('liming', 60)
book.report_grade('liming', 65)
print(book.average_grade('liming'))
#62

print(book.grades)
# {'liming': [60, 65], 'xiaoming': [90, 80]}
  • 1.2 使用字典维护程序的状态(中等复杂度示例)
# 记录每个学生对应的各科的多次成绩,最后求所有成绩的平均成绩
class BySubjectGradebook(object):
    def __init__(self):
        self.grades = {}

    def add_student(self, name):
        if name in self.grades:
            raise ValueError('no named {}'.format(name))
        self.grades[name] = {}

    def report_grade(self, name, subject, grade):
        if name not in self.grades:
            raise ValueError('no named {}'.format(name))
        by_subject = self.grades[name]
        grade_list = by_subject.setdefault(subject, [])
        grade_list.append(grade)

    def average_grade_of_all_subjects(self, name):
        subjects_grades = self.grades[name]
        total, count = 0, 0
        for grades in subjects_grades.values():
            total += sum(grades)
            count += len(grades)
        return total / count


book = BySubjectGradebook()
book.add_student('xiaoming')
book.report_grade('xiaoming','Math', 90)
book.report_grade('xiaoming', 'Math',80)
book.report_grade('xiaoming', 'Gym',70)
book.report_grade('xiaoming', 'Gym',80)
print(book.average_grade_of_all_subjects('xiaoming'))
# 80
  • 1.3 使用字典维护程序的状态(比较复杂,示例)
# 记录每个学生对应的各科成绩不同考试对应的成绩与权重比例
class WeightGradebook(object):
    def __init__(self):
        self.grades = {}

    def add_student(self, name):
        if name in self.grades:
            raise ValueError('no named {}'.format(name))
        self.grades[name] = {}

    def report_grade(self, name, subject, score, weight):
        if name not in self.grades:
            raise ValueError('no named {}'.format(name))
        by_subject = self.grades[name]
        grade_list = by_subject.setdefault(subject, [])
        grade_list.append((score, weight))

    def average_grade_of_all_subjects(self, name):
        subjects_grades = self.grades[name]
        score_sum, subject_count = 0, 0
        for subject, scores in subjects_grades.items():
            subject_avg, subject_total_score, total_weight = 0, 0, 0
            for score, weight in scores:
                subject_total_score += score*weight
                total_weight += weight
            subject_avg = subject_total_score / total_weight
            score_sum += subject_avg
            subject_count += 1
        print(subject_count)
        return score_sum / subject_count


book = WeightGradebook()
book.add_student('xiaoming')
book.report_grade('xiaoming', 'Math', 90, 0.6)
book.report_grade('xiaoming', 'Math', 80, 0.4)
book.report_grade('xiaoming', 'Gym', 70, 0.7)
book.report_grade('xiaoming', 'Gym', 80, 0.3)
print(book.grades)
print(book.average_grade_of_all_subjects('xiaoming'))
# {'xiaoming': {'Gym': [(70, 0.7), (80, 0.3)], 'Math': [(90, 0.6), (80, 0.4)]}}
# 2
# 79.5

2.1 使用辅助类来维护程序的状态

import collections

Grade = collections.namedtuple('Grade', ('score', 'weight'))


class Subject(object):
    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
        print('total:{},total_weight:{}'.format(total, total_weight))
        average_grade = total / total_weight
        print('average_grade:{}'.format(average_grade))
        return average_grade


class Student(object):
    def __init__(self):
        self._subjects = {}

    def subject(self, name):
        if name not in self._subjects:
            self._subjects[name] = Subject()
        return self._subjects[name]

    def average_grade(self):
        total, count = 0, 0
        for subject in self._subjects.values():
            total += subject.average_grade()
            count += 1
        print('total:{},count:{}'.format(total, count))
        return total / count


class Gradebook(object):
    def __init__(self):
        self._students = {}

    def students(self, name):
        if name not in self._students:
            self._students[name] = Student()
        return self._students[name]


book = Gradebook()
libai = book.students('libai')
liming = book.students('liming')
math = libai.subject('math')
math.report_grade(80, 0.1)
math.report_grade(90, 0.2)
print(libai.average_grade())
# total:26.0,total_weight:0.3
# average_grade:86.6666666667
# total:86.6666666667,count:1
# 86.6666666667
  • 2.2 将数据持久化
    将类对的属性与表中的字段对应,不同类型之间的关系可以使用外键关联,按需求实现多对多还是一对多等对应的关系,flask 框架可以使用 继承Model类,然后编写对应的字段

  • 3 总结
  1. 不要使用嵌套字典,不要使用长元组
  2. 简单不可变数据可以用namedtuple
  3. 字典复杂需要拆分为辅助类,比如uwsgi中的spool函数只接受一层级的字典,尽量简单,便宜维护

猜你喜欢

转载自www.cnblogs.com/max520liuhu/p/12046581.html