这一篇接着上篇8.2.2的内容讲述同一个实例
#8.3_Encapsulation and information hiding(封装和信息隐藏)
class Grades(object):
"""学生到成绩列表的映射关系"""
def __init__(self):
"""创建一个空的成绩册"""
self.students = []
self.grades = {}
self.isSorted = True
def addStudent(self,student):
"""假定student的类型是Student
把student添加到成绩册里"""
if student in self.students:
raise ValueError('Duplicate student')
self.students.append(student)
self.grades[student.getIdNum()] = []
self.isSorted = False
def addGrade(self, student, grade):
"""假定成绩是浮点数
把成绩添加到对应学生的成绩册上"""
try:
self.grades[student.getIdNum()].append(grade)
except:
raise ValueError('Student not in mapping')
def getGrades(self, student):
"""返回学生的成绩列表"""
try:#返回学生成绩的拷贝
return self.grades[student.getIdNum()][:]
except:
raise ValueError('Student not in mapping')
def getStudents(self):
"""返回成绩册中的学生列表"""
if not self.isSorted:
self.students.sort()
self.isSorted = True
return self.students[:]#返回学生列表的副本
#此处暂时忽略,8.3.1_生成器再回头注释上一句代码,使用以下代码
#for s in self.students:
#yield s
#返回副本会导致额外性能开销,但是直接返回实例变量进行赋值则会副作用:
#修改赋值的时候也会修改原值
#如:
#allStudents = course1.getStudents()
#allStudents.extend(course2.getStudents())
def gradeReport(course):
"""假定course类型为Grades"""
report = ''
for s in course.getStudents():
tot = 0.0
numGrades = 0
for g in course.getGrades(s):
tot += g
numGrades += 1
try:
average = tot/numGrades
report = report + '\n'\
+ str(s) + '\'s mean grade is ' + str(average)
except ZeroDivisionError:
report = report + '\n'\
+ str(s) + ' has no grades'
return report
ug1 = UG('Jane Doe', 2014)
ug2 = UG('John Doe', 2015)
ug3 = UG('David Henry', 2003)
g1 = Grad('Billy Buckner')
g2 = Grad('Bucky F. Dent')
sixHundred = Grades()
sixHundred.addStudent(ug1)
sixHundred.addStudent(ug2)
sixHundred.addStudent(g1)
sixHundred.addStudent(g2)
for s in sixHundred.getStudents():
sixHundred.addGrade(s, 75)
sixHundred.addGrade(g1, 25)
sixHundred.addGrade(g2, 100)
sixHundred.addStudent(ug3)
print(gradeReport(sixHundred))
#面向对象编程的两大核心概念:封装和信息隐藏
#如:Rafael = MITPerson()
#封装把数据属性和操作方法封装在一起,使用时就可以通过赋值创建新的实例
#并通过点标记法Rafael.getIdNum()进行访问该实例的属性,如学号、年龄。
#信息隐藏则是程序员隐藏数据属性的可见性,用户只能通过规范的类方法来访问数据
#举例说明就是,Rafael的idNum属性只能通过Rafael.getIdNum()来访问,而非Rafael.idNum
#这在Java和C++中是可以强制隐藏的,而python则没有,仍然可以用Rafael.idNum直接访问
#甚至,python还允许进行写操作,如Rafael.birtday = '8/7/2001'(在外部将Person的实例变量给赋值)
#和允许外部创建实例变量,如me.age = Rafael.getAge()(age是Person本没有的实例变量)
#信息隐藏的好处在于程序员可以随意修改类的具体实现,而不怕破坏用户的代码
#因此需要python程序员遵守规则,不在类的外部直接访问数据属性
附加对生成器的简要理解~
#8.3.1_Generator(生成器)_使大容量数据处理更有效率!
"""yield语句是类似于return语句但也十分不一样,含有它的函数一般被称为生成器函数"""
"""简单来说他们的区别在于,例子中return会返回一整个列表,来进行下一步的操作
而yield则通过for循环的搭配使用,逐个迭代每个需要下一步操作的值
即迭代列表里的一个元素,然后把for循环挂起跳出,完成之后的操作后再回到for循环
回到原来的位置迭代下一个元素,同理继续操作"""
"""这里的好处在于,传统的函数返回一整个列表,当这个列表的容量很大的时候,所占的内存就会很大,
严重影响性能;而生成器函数每次返回列表中的一个元素进行操作,内存极小,还可以再回到原位置,
继续迭代下一个元素继续操作,性能和效率上优劣之分就很明显了。"""
#可以回看getStudents函数,用以下程序测试一下
import time
t1 = time.time()
book = Grades()
book.addStudent(Grad('Julie'))
book.addStudent(Grad('Charlie'))
for s in book.getStudents():
print(s)
t2 = time.time()
print(t2 - t1) #用于测试运行速度
#可以看看这里,有更深的了解噢~https://blog.csdn.net/S_o_l_o_n/article/details/81878032