Effective Python学习笔记(一) ——辅助类的使用

来源:互联网 发布:unity3d easyar 编辑:程序博客网 时间:2024/05/21 21:37

一年前刚刚接触Python的时候,很好奇面向对象的语言到底有什么优势?感觉类不如字典好用,字典不如列表好用。尴尬(请原谅编程小白的无知)

然后慢慢开始接触pygame,kivy,pyQt,numpy,scipy,sklearn,pandas各种库,发现各路大神真的很喜欢用类啊,实现一个功能的实现只要一行代码,用起来不要太爽。。.

经过一番学(piao)习(qie),我也开始鸟枪换炮啦,代码也能写成下面这个样子:

class SimpleGradebook(object): #学生成绩册    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)
这个简单的类中使用了一一对应的字典,可以很好地保存学生成绩册这个对象在其生命周期里的动态内部结构。但是随着功能的增多,一一对应的字典很容易出现问题。比如我们要扩充SimpleGradebook类,使它能够按照科目来保存成绩,而不是像原来那样,把所有科目的成绩保存在一起。再比如说,我们除了要记录每次考试的成绩,还要记录该成绩所占的权重。那么嵌套式的结构可能是一个很好的选择,这里我们试着把这种嵌套式的结构重构为类。

我们先写一个表示科目的类,该类表示一系列考试成绩:

class Subject(object):    def __init__(self):        self._grades = []    def report_grade(self, score, weight):        self._grades.append(Grade(score, weight)) #这里的Grade是一个namedtuple(具名元组)    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

在这串代码中,为了简化过长的元组(含有超过两项的元素),不妨使用collections模块中的namedtuple(具名元组)来实现一个精简的数据类进行辅助.

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

构建这样的具名元组是,既可以位置指定其中的项,也可以按关键字来指定,很容易就能从namedtuple迁移到自己定义的类。


下面我们继续编写表示学生的类,该类包含学生正在学习的各种课程.

class Student(object):    def __init__(self):        self._subjects = {}    def subject(self, name):        if name not in self._subjects:            self._subjects[name] = Subject() #调用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        return total/count

最后,编写包含所有学生考试成绩的容器类,该容器以学生的名字为键,并且可以动态地添加学生.

class Gradebook(object):    def __init__(self):        self._students = {}    def student(self,name):        if name not in self._students:            self._students[name] = Student() #调用student类        return self._students[name]

辅助类的代码量确实比较大。但是类的一大好处就是能使程序便于理解,而且这种形式的代码写起来也比原来更为清晰,更易扩展.


要点:

1.不要使用包含其他字典的字典,也不要使用过长的元组.

2.如果容器中包含简单而不可变的数据,那么可以先使用namedtuple来表示,待以后有需要时,再修改为完整的类.

3.保持内部状态的字典如果比较复杂,就应该把这些代码拆解为多个辅助类.



原创粉丝点击