be possible to write client code using the specification of student and have it work correctly on transferstudent converselythere is no reason to expect that code written to work for transferstudent should work for arbitrary types of student encapsulation and information hiding as long as we are dealing with studentsit would be shame not to make them suffer through taking classes and getting grades class grades(object)""" mapping from students to list of grades""def __init__(self)"""create empty grade book""self students [self grades {self issorted true def addstudent(selfstudent)"""assumesstudent is of type student add student to the grade book""if student in self studentsraise valueerror('duplicate student'self students append(studentself grades[student getidnum()[self issorted false def addgrade(selfstudentgrade)"""assumesgrade is float add grade to the list of grades for student""tryself grades[student getidnum()append(gradeexceptraise valueerror('student not in mapping'def getgrades(selfstudent)"""return list of grades for student""try#return copy of student' grades return self grades[student getidnum()][:exceptraise valueerror('student not in mapping'def getstudents(self)"""return list of the students in the grade book""if not self issortedself students sort(self issorted true return self students[:#return copy of list of students figure class grades this substitution principle was first clearly enunciated by barbara liskov and jeannette wing in their paper" behavioral notion of subtyping