'''lecture_29_csstudent.py Show inheritance with the CSStudent (child class) that inherits from ColbyStudent (parent class) TODO: 1. is-a relationship 2. CSStudent constructor signature: def __init__(self, name, year, favLang) - Show with redundant code. - Code reuse: call parent constructor (with super() and directly) 3. When instance variables in parent inherited by child - Show __init__ with/without calling parent constructor 4. set/get methods for CSStudent-specific vars - Show access with ColbyStudent and CSStudent objects 5. Parent and inherited versions of methods - Write printGrades in parent (100 point scale) - Show OVERRIDE in child (30 point scale) - Show EXTENDING in (both scales) 6. Symbol table for `newCSStudent.printGrades()` and `newColbyStudent.printGrades()` Oliver W. Layton CS 151: Computational Thinking: Visual Media Fall 2020 ''' class ColbyStudent: lastDayOfClass = 'Nov 24' def __init__(self, name, year=2022): # Initialization data self.name = name self.year = year # Derived data self.grades = [] self.gpa = 0.0 def getName(self): return self.name def getGrades(self): # return self.grades # shallow copy / nickname return self.grades[:] # deep copy by independence rule for slicing lists def addGrade(self, newGrade): self.grades.append(newGrade) def getLastDay(self): return ColbyStudent.lastDayOfClass def printGrades(self): print(self.grades) class CSStudent(ColbyStudent): def __init__(self, name, year, favLang): # Leveraging/running code in parent class # Parent class has another name: super class # Child is called subclass # If I comment out call to parent constructor, self.name and self.year are NOT defined # EXTENDING __init__ super().__init__(name, year) # self.name and self.year get defined # Another way to access parent version of a method: # ColbyStudent.__init__(self, name, year) self.favLang = favLang # If super class init not called, self.gpa never defined so following # line of code will crash # print('GPA is', self.gpa) # print('Accessing getFavLang method:', self.getFavLang()) # Duplicated code from parent class. Better to call parent constructor # self.name = name # self.year = year # self.favLang = favLang def getFavLang(self): return self.favLang def getName(self): return self.name # I am OVERRIDING the parent method (unlinking parent and child printGrades method) # We want to print CS student grades out of 30, not 100 # Override: REPLACES behavior of parent with child version def printGrades(self): # grades = self.getGrades() # Call child version of this method (inherited version) grades = super().getGrades() # Call parent version of this method # Let's convert to 30 point scale for i in range(len(grades)): grades[i] = 30*grades[i]/100 print(grades) # EXTENDING: Do specific stuff in child version of method, but also call parent version. def printGrades(self): # grades = self.getGrades() # Call child version of this method (inherited version) # grades = super().getGrades() # Call parent version of this method grades = self.grades[:] # Let's convert to 30 point scale for i in range(len(grades)): grades[i] = 30*grades[i]/100 print(grades) print('Here are the grades also on a 100 point scale') super().printGrades() # An override. Now child and parent versions are not linked/duplicates # def getLastDay(self): # return 'Dec 4' # An extend. Now child and parent versions are not linked/duplicates # def getLastDay(self): # print('Here is the Colby Student last day first:') # print(super().getLastDay()) # return 'Dec 4' if __name__ == '__main__': colbyStu = ColbyStudent('Jane', 2022) colbyStu2 = ColbyStudent('Lilly', 2023) csStu = CSStudent('Jim', 2024, 'Python') # Let's access a method that is inherited by CSStudent (child) from ColbyStudent (parent) # print('CS Student name', csStu.getName()) print('CS Student fav language:', csStu.getFavLang()) # colbyStu.addGrade(80) # colbyStu.addGrade(90) # colbyStu.addGrade(100) # print('Colby Student grades:') # colbyStu.printGrades() # [80, 90, 100] # csStu.printGrades() # [] because IV data is independent/unique to each object # csStu.addGrade(70) # csStu.addGrade(100) # print('CS Student grades:') # Looks in CSStudent class if there is a method override (we defined a special version) # Otherwise looks at inherited version from parent # csStu.printGrades() # Use copied version of method, inherited from parent # print('CS Student name', csStu.getName()) # colbyStu2.printGrades() # Overriding example print('Colby Student last day:', colbyStu.getLastDay()) # print('CS Student last day:', csStu.getLastDay()) # calling inherited version of method print('CS Student last day:', csStu.getLastDay()) # After override