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

  • flight.py - defines a Flight 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

  • StudentRecord

    • data - name, age, major

    • methods - get_name, etc.

  • Earthquake

    • data - id, magnitude, location, date

    • methods - get_id, get_location_full, 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 Flight class

In flight.py, define a Flight class:

  • Each Flight has an origin (str), destination (str), fare (float), and available seats (int)

  • The constructor should take the four values as parameters.

  • Write getters for the four instance variables.

  • Write a setter for the fare. If the new value is zero or negative, display an error message and do not change the fare.

  • Write a claim_seats method that is given an int indicating the number of seats to claim, and reduces the number of available seats by that value. If the number being claimed is greater than the number that are available, display an error message and do not change the number of available seats.

  • Write a __str__ method the returns a string representing the data in the object. This should return a string, not print it.

  • Write some tests of the class in main.

  • Call main only if __name__=='__main__'