《Effective Python》笔记——第3章 类与继承

一、尽量用辅助类来维护程序的状态

如下,用字典存储简单数据

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]
        return sum(grades) / len(grades)    # 计算一个学生的平均成绩


book = SimpleGradebook()
book.add_student('ss')
book.report_grade('ss', 90)
book.report_grade('ss', 100)
print(book.average_grade('ss'))

如下示例,多层字典结构,代码变得负责且难读

class SimpleGradebook():
    def __init__(self):
        self.__grades = {}

    def add_student(self, name):
        self.__grades[name] = {}    # 一个学生的成绩加入科目分类,所以用字典存储

    def report_grade(self, name, subject, score):
        by_subject = self.__grades[name]
        grade_list = by_subject.setdefault(subject, [])     # 存在该科目则返回已有列表,不存在则返回一个空列表
        grade_list.append(score)

    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


book = SimpleGradebook()
book.add_student('ss')
book.report_grade('ss', 'Math', 90)
book.report_grade('ss', 'Math', 100)
print(book.average_grade('ss'))

使用嵌套结构重构类,书上的代码有错,以下是github上本书第二版的最新示例代码

from collections import namedtuple, defaultdict

Grade = namedtuple('Grade', ('score', 'weight'))    # 具名元组


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]


book = Gradebook()
albert = book.get_student('ss')
math = albert.get_subject('Math')
math.report_grade(75, 0.05)
math.report_grade(65, 0.15)
math.report_grade(70, 0.80)
gym = albert.get_subject('Gym')
gym.report_grade(100, 0.40)
gym.report_grade(85, 0.60)
print(albert.average_grade())

 

二、简单接口应该接受函数,而不是类的实例

 简单接口使用函数,不要用类;

通过__call__方法,可以使类实例像函数一样被调用

如果需要保存状态,应该定义新的类,而不是带状态的闭包。

 

三、以@classmethod形式的多态去通用地构建对象

 pass

四、用super初始化父类

pass

五、多用public属性,少用private属性

pass

六、从collections.abc中继承基类

简单子类可以直接从python的标准类型中继承(如list,dict,set,tuple等)

collections.abc中有很多基类

posted @ 2019-06-21 21:51  沄持的学习记录  阅读(306)  评论(0编辑  收藏  举报