Weeks 12: Classes and Objects

Week 12 Goals

  • Understand connection of instances (objects) + classes

  • Understand key attributes of class definitions

    • member variables

    • constructor

    • accessors/getters

    • mutators/setters

  • Define classes with basic types (int, float, …​)

  • Be able to write Python classes from scratch given an English specification

Week 12 Files

  • employee.py - defines an Employee class

  • employee_test.py - code that imports and uses Employee class

  • student.py - defines a Student class

Object-Oriented Programming Revisited

Objects combine data and functionality (methods) together. We’ve seen lots of examples of objects in the class so far:

  • list

    • data - length, and all the data inside

    • methods - append, sort

  • str

    • data - each character in the string, the number of chars in the string

    • methods - isdigit, lower, split

  • Point

    • data - x, y

    • methods - getX, getY, draw

  • Circle

    • data - center, radius

    • methods - getCenter, getRadius, setFill, setOutline, setWidth, draw

  • Novel

    • data - title, author, year, gender, rank, rating, number of ratings

    • methods - get_title, get_author, etc.

Keep in mind the following terminology:

  • class: a template for how to build objects of a new type

  • object: a particular instance of a class that has its own data values in a running program

  • dot notation: how you call the methods of a class: <instance>.<method>(<arg1>, …​)

Designing a Class

In these notes, we will define our own class to represent the employee of an organization.

In designing this class, we should consider its data (or "instance variables" or "fields") and its functionality (or "methods").

For example, our employee may include the following data:

  • name, represented as a string

  • identification number (idno), represented as an int

  • annual salary, represented as a float

We can use methods to allow other classes to read this data. These methods are called "accessors" or "getters" because they provide a means of accessing the data and typically start with the word "get":

  • get_name provides access to the name

  • get_ID provides access to the idno

  • get_salary provides access to the salary

We may also want to allow other classes to modify this data. These methods are called "mutators" or "setters" because they provide a means of mutating/changing the data and typically start with the word "set". In our case, we’ll say that only the name can be directly changed:

  • set_name changes the name

Another way of modifying data is to provide a means of changing it but not setting it directly. This is still considered a "mutator" because it changes the value of the field. We’ll provide a method for increasing the salary:

  • increase_salary increases the salary by a given amount

Last, there are two other important methods that are used by Python:

  • __init__ is the constructor, which is the method that is called when an object is created. It is used to initialize the fields.

  • __str__ is a method that returns a string representation of this object. It is called when we use the print() function to print the object.

Defining a Class

Now that we’ve designed the class, we can write the code for it.

Our class will be called Employee; it is the convention that Python class names start with uppercase letters.

The file that contains the definition of the class will be employee.py. Although it is not required that it has the same name as the class, it makes it easy to understand, and the convention is that the file name starts with a lowercase letter.

Key to understanding the code below is the variable called self. This is a variable that refers to the object itself, and allows us to access its fields using dot notation, e.g. self.salary.

You’ll notice that self is the first parameter listed for all of these functions. Don’t forget to list it first and to use it within the function!

"""
Class to represent an employee at an organization.
This class includes the employee's name, ID number, and salary.
"""

class Employee:

    def __init__(self, name, idno, salary):
        """
        This is the constructor, which is the function that is called
        when an instance of the class (object) is created.
        Parameters:
         * self: refers to this object, i.e. the object being created
         * name (str): the name of the employee
         * idno (int): the employee's ID number
         * salary (float): the employee's annual salary
        Returns: None. The name, idno, and salary are modified as a result.
        """
        # note that we need to refer to the name instance of
        # "this object" using the parameter "self"
        self.name = name
        self.idno = idno
        self.salary = salary

    def get_name(self):
        """
        Accessor ("getter") method to access the employee's name.
        Parameter:
         * self: refers to this object; it is implicitly passed as
           an argument when this method is called
        Returns: the value of the name field (str)
        """
        return self.name # note that it is not simply "return name"

    def set_name(self, new_name):
        """
        Mutator ("setter") method to change the employee's name.
        Parameters:
         * self: refers to this object
         * new_name (str): the new name for this employee
        Returns: None. The name field is modified as a result.
        """
        self.name = new_name # note that it is not "name = new_name"

    def get_ID(self):
        """
        Accessor method for employee's ID number.
        """
        return self.idno

    def get_salary(self):
        """
        Accessor method for employee's salary.
        """
        return self.salary

    def increase_salary(self, amount):
        """
        Method that increases the employee's salary by the given amount.
        """
        self.salary = self.salary + amount

    def __str__(self):
        """
        Method that creates and returns a string representation of this object.
        This allows us to print the object using the print() function.
        """
        return "Name: %s; ID: %d; Salary: %.2f" % \
            (self.name, self.idno, self.salary)

Creating and Using Instances (Objects) of a Class

Now that we’ve defined the Employee class, we can create instances of it in a program and then call methods on those objects.

The code below should look similar to past examples and labs that used objects, but now we are using our own custom Employee class!

"""
Code that allows us to test the functionality of the Employee class.
"""

# this is so that we can access the Employee class in this file
from employee import *

def main():
    # this creates an Employee object using the constructor
    e1 = Employee("Grace Hopper", 8675309, 135000)

    # these call the accessor/getter methods
    print(e1.get_name())
    print(e1.get_ID())
    print(e1.get_salary())

    # when we pass the object to print(), it calls the __str__() method
    print(e1)

    # now we can call the mutator methods
    e1.set_name("Grace Brewster Hopper")
    e1.increase_salary(10000)

    # now we should see the updated values
    print(e1)

    # create a separate instance/object of this class
    e2 = Employee("Ada Lovelace", 1234567, 125000)

    # its fields have different values from those in e1
    print(e2.get_name())
    print(e2.get_ID())
    print(e2.get_salary())

    # when we change it, it doesn't change e2
    print(e1.get_salary())
    e2.increase_salary(5000)
    print(e1.get_salary()) # e1's salary has not changed

main()

Practice creating a Student class

In student.py, define a Student class

  • Each Student has a name, class year, and major.

  • The constructor should take the name and class year as parameters; the major should be set to "Undecided".

  • Write getters for the name, year and major.

  • Write a setter for the year. If the year is not between 2025-2028, don’t change the year and print a message.

  • Write a setter for the major. If the major is not in a small list of majors (e.g. "Comp Sci", "Economics", "Philosophy", "Undecided"), don’t change the major and print a message. You can choose the set of majors you want to accept.

  • Write some tests of the class in main.

  • Call main only if __name__=='__main__'