Start learning free

LESSON 558 OF 569 · OBJECT-ORIENTED PROGRAMMING - CHALLENGES

Employees and Managers in Python: Inheritance and super()

Practice O(1) Read the full explanation

A company pays every employee a salary. A manager is an employee too, but earns a bonus on top of the salary. Write the two classes so that a manager reuses everything an employee has, and changes only how its pay is worked out.

Implement the class Employee:

  • Employee(name, salary) creates an employee. The name and the salary are private to Employee.
  • pay() returns the salary.
  • describe() returns the text <name> earns <pay>, where the amount is what pay() returns, for example Ana earns 3000.

and the class Manager, which inherits from Employee:

  • Manager(name, salary, bonus) lets the parent's constructor store the name and the salary, and stores the bonus itself, private to Manager.
  • pay() returns the parent's pay() plus the bonus. Call the parent's version, as in the lesson Calling the Parent Method: the salary is private to Employee, and the parent's pay() is what knows how an employee is paid.
  • describe() is not written again: Manager inherits it unchanged. Because describe() calls pay(), a manager's description shows the manager's pay, bonus included.

The input is a list of people, one per line: employee name salary or manager name salary bonus. For each line, the code that tests your classes creates that object and prints what its describe() returns, on a line of its own. The starter code spells these names the way your language does.

 

Example 1:

Input:
    employee Ana 3000
    manager Bob 4000 1000
Output:
    Ana earns 3000
    Bob earns 5000
Explanation:
Ana's pay is her salary. Bob's pay is the parent's pay, his salary 4000, plus his bonus 1000.
Bob's describe() is Employee's describe(), but the pay() it calls is Manager's.

Example 2:

Input:
    manager Cleo 5000 0
    employee Dan 5000
Output:
    Cleo earns 5000
    Dan earns 5000
Explanation: A manager whose bonus is 0 earns exactly the salary, like an employee.

Example 3:

Input:
    manager Eve 7000 2500
    employee Finn 2800
    employee Gus 3100
    manager Hana 6000 500
Output:
    Eve earns 9500
    Finn earns 2800
    Gus earns 3100
    Hana earns 6500
Explanation: Employees and managers come in any order, and each object keeps its own name and numbers.

 

Constraints:

  • 0 <= salary <= 106
  • 0 <= bonus <= 106
  • A name is one word of 1 to 20 English letters. Two people may have the same name.
  • At most 100 people per test case.
STEP 1 OF 7
    Ctrl + Enter to check

    PYTHON · OBJECT-ORIENTED PROGRAMMING - CHALLENGES

    Employees And Managers in Python, explained

    Problem overview

    A company pays every employee a salary. A manager is an employee too, but earns a bonus on top. You write two classes so that Manager reuses everything Employee has and changes only how its pay is worked out.

    • Employee(name, salary) keeps the name and salary, pay() returns the salary, and describe() returns text like Ana earns 3000.
    • Manager(name, salary, bonus) inherits from Employee. Its pay() returns the parent's pay plus the bonus. It does not write describe() again.

    For Employee("Ana", 3000) the description is Ana earns 3000. For Manager("Bob", 4000, 1000) it is Bob earns 5000, although only Employee contains the code of describe().

    Approach: inherit, override one method

    Writing class Manager(Employee) makes Manager a child of Employee. A manager object has every method the parent has. A child can override a method by defining one with the same name, and here it overrides only pay.

    The clever part is describe. It builds its text from self.pay(), not from the salary attribute. When describe runs on a manager, self is the manager, so self.pay() finds Manager.pay, and the bonus appears in the text without a second describe. On an employee, the same line finds Employee.pay.

    The same idea explains Manager.pay. It calls super().pay(), which runs the parent's version, and adds the bonus. The salary stays in the code that owns it. Writing self.pay() inside Manager.pay would be a mistake: it calls the same method again, and again, until Python gives up with a RecursionError.

    Step by step

    1. In Employee.__init__, store the name in self._name. The underscore marks it as private by convention.
    2. Store the salary in self._salary.
    3. pay returns self._salary.
    4. describe returns the name, then " earns ", then str(self.pay()), joined with +. str is needed because + can't join text and a number.
    5. In Manager.__init__, call super().__init__(name, salary). The parent stores the name and the salary on this manager.
    6. Store the bonus in self._bonus. It is the one thing Employee doesn't know about.
    7. Override pay to return super().pay() + self._bonus.

    The solution in Python

    class Employee:
        def __init__(self, name, salary):
            self._name = name
            self._salary = salary
        def pay(self):
            return self._salary
        def describe(self):
            return self._name + " earns " + str(self.pay())
    class Manager(Employee):
        def __init__(self, name, salary, bonus):
            super().__init__(name, salary)
            self._bonus = bonus
        def pay(self):
            return super().pay() + self._bonus
    

    Using it:

    people = [Employee("Ana", 3000), Manager("Bob", 4000, 1000),
              Manager("Cleo", 5000, 0), Employee("Dan", 5000)]
    for p in people:
        print(p.describe())
    
    Ana earns 3000
    Bob earns 5000
    Cleo earns 5000
    Dan earns 5000
    

    Cleo is a manager with a bonus of 0, so she earns exactly her salary, like Dan.

    Python details

    • The parent's constructor isn't called for you. If Manager.__init__ skipped super().__init__(...), a manager would have no _name or _salary, and describe() would fail.
    • super() takes no arguments inside a method. It gives access to the parent's methods.
    • Private by convention. The underscore doesn't stop a subclass from reading self._salary. The lesson has Manager ask the parent's pay() instead, so only Employee needs to know how an employee is paid.

    Edge cases and common mistakes

    • Calling self.pay() inside Manager.pay. The method calls itself forever and ends in a RecursionError. Use super().pay().
    • Reading self._salary in describe. It would work for employees, but a manager's description would leave out the bonus.
    • Joining text and a number. self._name + " earns " + self.pay() raises a TypeError. Wrap the number in str.
    • Writing describe again in Manager. Not needed: it is inherited, and it already calls the right pay.
    • Complexity. Every method is a few operations, so each is O(1).

    Testing

    Employees and managers can come in any order, and each object keeps its own name and numbers:

    • Manager("Eve", 7000, 2500).describe() gives Eve earns 9500.
    • Employee("Finn", 2800).describe() gives Finn earns 2800.
    • Employee("Gus", 3100).describe() gives Gus earns 3100.
    • Manager("Hana", 6000, 500).describe() gives Hana earns 6500.

    If a manager skips super().__init__, calling describe() fails with AttributeError: 'NoSuper' object has no attribute '_name' (the class name in the message is whatever your class is called).

    Keep going with Python500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free