Implementing a Class Hierarchy
00:00 Now that you understand the basics of inheritance and composition, it’s time to apply them to a real project. Throughout the rest of this course, you are going to build a simple application that could be used by a human resources department to track employees’ productivity and calculate their payrolls. As you code, you’ll learn about some new object-oriented programming techniques and you’ll get some invaluable practice with inheritance and composition.
I’ll print a blank line just to keep things separated. Okay, this is a good start, but we haven’t defined what it means to be an employee. According to this class, employees must have attributes for
.id, and they must implement a
Any class that implements this
IPayrollCalculator is one that can be passed into this
PayrollSystem. That’s because the
PayrollSystem requires the same members listed in the
I’ll create a new class here called
Employee. Because this is the base class of everything else, it won’t explicitly inherit from anything, but remember that it’s still inheriting from that
object superclass behind the scenes.
According to our UML diagram, this
Employee must contain two instance methods,
.name. I’ll create an
.__init__() method with parameters for
name, and then assign those to the instance attributes.
Now, let’s create our first specialized employee class. The first class is
SalaryEmployee, which will act just like a regular employee, except they will also have a
.weekly_salary instance attribute that will be used in their
So first, I will create the class, and we want to make sure we’re inheriting from
Employee. At this point,
SalaryEmployee is functionally identical to
Employee, but that’s pretty boring. Just like before, I’m going to create an
.__init__() method, but this time I will also accept a
weekly_salary as a parameter.
This will allow us to access the instance methods declared in the parent from within the child. If we were to omit the
.__init__() method in the child, it would automatically inherit everything from the parent.
But once we declare this
.__init__() method in the child, it covers up all of the instance attributes in the parent, and we must set them manually by calling the
.__init__() method in the parent.
In order for this class to conform to
IPayrollCalculator, which is required to be used by the
PayrollSystem class, it must also implement a
.calculate_payroll() method that defines how a
SalaryEmployee is paid. To do that, I’ll create the
.calculate_payroll() method, passing in
self as a parameter.
And I will simply return the
.weekly_salary instance attribute. This seems kind of trivial now, but later on, you’ll see why it’s important that we returned this instance attribute through a method.
At this point, you might be wondering, “Why do we need to call the
.__init__() method of the parent when we instantiate a child class?” The reason for that is because the child class inherits the attributes of the parent, but it can’t use them unless it initializes them with some value.
Like I mentioned before, if we didn’t call the parent’s
.__init__() method with the required arguments but we did include our own
.__init__() method in this child class, then our
SalaryEmployee would just have a
.weekly_salary attribute, but no
It wouldn’t really be an
Employee, either, and so it wouldn’t conform to the
IPayrollCalculator interface. Again, if you don’t declare an
.__init__() method in the child class, then it will use its parent’s
.__init__() method by default and call that when you try to instantiate the child class.
But if you do declare an
.__init__() method in the child class, that will override the
.__init__() method in the parent, so you usually want to call the parent’s
.__init__() method manually, either by name or with the
super() function, like we did here.
Next, let’s create the
HourlyEmployee, which will also inherit from
Employee. This type of employee is paid by the hour, and so it will also need two additional instance attributes:
The last specialized class we need to create is the
CommissionEmployee. This class is a little special, though, and that’s because a commission employee receives both a commission and a weekly salary—lucky them! Because they are technically also a salary employee, we want to make them inherit from
SalaryEmployee instead of the base
Employee class. They share so much in common, so we might as well.
It’s an instance attribute of its parent,
SalaryEmployee. We initialized the
.weekly_salary, so we can use it, but instead of accessing that attribute directly with the
super() function, let’s think about a better way to do this.
That being said, let’s create a new variable called
fixed, which will store the
.weekly_salary value obtained by calling the parent class’s
.calculate_payroll() method. Now, this might seem a little bit strange because right now the parent class’s
.calculate_salary() method just returns the
.weekly_salary attribute. I mean, we could have just accessed that directly. But think about this: what if the way we calculate the
SalaryEmployee salary changes in the future?
That would mean that we’d change the implementation of its
.calculate_payroll() method in the
SalaryEmployee class, and because a
CommissionEmployee is a
SalaryEmployee, we’d want that change to trickle down to the
By making the
CommissionEmployee obtain its
.weekly_salary component through the
.calculate_payroll() method, we’ve future-proofed this relationship from any changes in the parent.
All that’s left to do is test it by creating some objects. To do that, I’m first going to create a new file called
program.py. This will be the entry point of our HR program, and so this is the script we should always run.
or you might run into some issues. The first kind of employee we’re going to create is the
SalaryEmployee. We’ll get that object with
hr.SalaryEmployee passing in an
'John Smith', and a
I’ll create the
HourlyEmployee object the same way, except this employee will work
40 hours a week at a rate of
15 dollars per hour. For the
CommissionEmployee, I want them to get a base salary of
1000 dollars a week, plus
250 dollars in commissions.
Become a Member to join the conversation.