Classes, Objects, and Inheritance¶
In today’s lecture, we will continue our discussion of object oriented programming in Python.
Example: Name
class¶
If our class represents names, we can choose how these names are printed.
class Name:
"""Class to represent a person's name."""
__slots__ = ['_f', '_m', '_l']
def __init__(self, first, last, middle=''):
print("__init__ is running")
self._f = first
self._m = middle
self._l = last
def getFirst(self):
return self._f
def __str__(self):
print("in __str__")
# if the person has a middle name
if len(self._m):
return '{}. {}. {}'.format(self._f[0], self._m[0], self._l)
else:
return '{}. {}'.format(self._f[0], self._l)
n1 = Name('Rohit', 'Bhattacharya')
n2 = Name('Jeannie', 'Albrecht', 'Raye')
__init__ is running
__init__ is running
print(n1)
print(n2)
in __str__
R. Bhattacharya
in __str__
J. R. Albrecht
n1.__str__()
in __str__
'R. Bhattacharya'
Defining a method for initials¶
Now let’s implement a method for generating someone’s initials.
class Name:
"""Class to represent a person's name."""
__slots__ = ['_f', '_m', '_l']
def __init__(self, first, last, middle=''):
self._f = first
self._m = middle
self._l = last
def initials(self):
if len(self._m):
return '{}. {}. {}.'.format(self._f[0], self._m[0], self._l[0]).upper()
else:
return '{}. {}.'.format(self._f[0], self._l[0]).upper()
def __str__(self):
# if the person has a middle name
if len(self._m):
return '{}. {}. {}'.format(self._f[0], self._m[0], self._l)
else:
return '{}. {}'.format(self._f[0], self._l)
n1 = Name('Steve', 'Freund', 'N')
n1.initials()
'S. N. F.'
n2 = Name('Lida', 'Doret', 'P')
n2.initials()
'L. P. D.'
Inheritance¶
Inheritance is the capability of one class to derive or inherit the properties from another class. The benefits of inheritance are:
Often represents real-world relationships well
Provides reusability of code, so we don’t have to write the same code again and again
Allows us to add more features to a class without modifying it
Inheritance is transitive in nature, which means that if class B inherits from class A, then all the subclasses of B would also automatically inherit from class A.
When a class inherits from another class, all methods and attributes are accessible to subclass, except private attributes (indicated with __)
Person example¶
Suppose we want to define classes to represent all people on campus.
We can start with a parent or “super” class that defines the attributes common across all groups of people.
class Person:
__slots__ = ['_name']
def __init__(self, name):
self._name = name
def getName(self):
return self._name
def __str__(self):
return self._name
Now suppose we define three subclasses that all inherit from Person but also add additional functionality: Student, Faculty, Staff.
Students inherit from the Person class, but also add attributes and getter methods for year and major.
class Student(Person):
__slots__ = ['_year', '_major']
def __init__(self, name, year, major):
# call __init__ of Person (the super class)
super().__init__(name)
self._year = year
self._major = major
def getYear(self):
return self._year
def getMajor(self):
return self._major
def setMajor(self, major):
self._major = major
def __str__(self):
return "{}, {}, {}".format(self._name, self._major, self._year)
Faculty also inherits from Person, but unlike Student, it does not define attributes for year and major since that does not apply to Faculty. Instead, the Faculty class defines attributes for dept and office.
class Faculty(Person):
__slots__ = ['_dept', '_office']
def __init__(self, name, dept, office):
# call __init__ of Person (the super class)
super().__init__(name)
self._dept = dept
self._office = office
def getDept(self):
return self._dept
def getOffice(self):
return self._office
Finally, the Staff class also inherits from Person. It adds an attribute for fulltime. Note the use of the getStatus()
getter method to return a string even though _fulltime
is being stored as a boolean attribute.
class Staff(Person):
# fulltime is a Boolean
__slots__ = ['_fulltime']
def __init__(self, name, fulltime):
# call __init__ of super class
super().__init__(name)
self._fulltime = fulltime
def getStatus(self):
if self._fulltime:
return "fulltime"
return "partime"
def __str__(self):
return "{}, {}".format(self.getName(), self.getStatus())
Now let’s try using our classes.
jane = Student("Jane", 2024, "CS")
# inherited from Person
jane.getName()
'Jane'
type(jane)
__main__.Student
# defined in Student
jane.getMajor()
'CS'
jane.setMajor("Math")
jane.getMajor()
'Math'
print(jane)
Jane, Math, 2024
rohit = Faculty("Rohit", "CS", "TBL 309B")
rohit.getName()
'Rohit'
rohit.getDept()
'CS'
print(rohit)
Rohit
# this doesn't work since instances of Faculty do
# not have a major attribute
rohit.getMajor()
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
/var/folders/md/kwd9nc_d2ns0hw9wsvdrnt2c0000gn/T/ipykernel_55965/2826432291.py in <module>
1 # this doesn't work since instances of Faculty do
2 # not have a major attribute
----> 3 rohit.getMajor()
AttributeError: 'Faculty' object has no attribute 'getMajor'
fred = Staff("Fred", False)
print(fred)
Fred, partime
fred.getStatus()
'partime'