Part 8

More examples of classes

Example 1: the Rectangle class

Let's have a look at a class which models a rectangle in two-dimensional space:

class Rectangle:
    def __init__(self, left_upper: tuple, right_lower: tuple):
        self.left_upper = left_upper
        self.right_lower = right_lower
        self.width = right_lower[0]-left_upper[0]
        self.height = right_lower[1]-left_upper[1]

    def area(self):
        return self.width * self.height

    def perimeter(self):
        return self.width * 2 + self.height * 2

    def move(self, x_change: int, y_change: int):
        corner = self.left_upper
        self.left_upper = (corner[0]+x_change, corner[1]+y_change)
        corner = self.right_lower
        self.right_lower = (corner[0]+x_change, corner[1]+y_change)

A new Rectangle is created with two tuples as arguments. These tuples contain the x and y coordinates of the upper left corner and the lower right corner. The constructor calculates the height and width of the rectangle based on these values.

The methods area and perimeter calculate the area and perimeter of the rectangle based on the height and width. The method move moves the rectangle by the x and y values given as arguments.

The rectanlge is represented in a coordinate system where the x coordinates increase from left to right, and the y coordinates increase from top to bottom. This is a common way of handling coordinates in programming because it is often easier and more natural to consider the top left corner of the computer screen as the point where x and y equal zero.

The following program tests the Rectangle class:

rectangle = Rectangle((1, 1), (4, 3))
print(rectangle.left_upper)
print(rectangle.right_lower)
print(rectangle.width)
print(rectangle.height)
print(rectangle.perimeter())
print(rectangle.area())

rectangle.move(3, 3)
print(rectangle.left_upper)
print(rectangle.right_lower)
Sample output

(1, 1) (4, 3) 3 2 10 6 (4, 4) (7, 6)

Printing an object

When you have an object created from a class defined by yourself, the default reaction to calling the print command with that object as its argument is not very informative:

rectangle = Rectangle((1, 1), (4, 3))
print(rectangle)

The printout should look a bit like this:

Sample output

<main.Rectangle object at 0x000002D7BF148A90>

Obviously, we want more control over what is printed out. The easiest way to do this is to add a special __str__ method to the class definition. Its purpose is to return a snapshot of the state of the object in string format. If the class definition contains a __str__ method, the value returned by the method is the one printed out when the print command is executed.

So, let's add a __str__ method definition to our Rectangle class:

class Rectangle:

    # ...the rest of the class goes here the same as above...

    # This method returns the state of the object in string format
    def __str__(self):
        return f"rectangle {self.left_upper} ... {self.right_lower}"

Now the print command produces something more user-friendly:

rectangle = Rectangle((1, 1), (4, 3))
print(rectangle)
Sample output

rectangle (1, 1) ... (4, 3)

The __str__ method is perhaps more often used for formulating a string representation of the object with the str function, as seen in the following program:

rectangle = Rectangle((1, 1), (4, 3))
str_rep = str(rectangle)
print(str_rep)
Sample output

rectangle (1, 1) ... (4, 3)

There are many more special underscored methods which can be defined for classes. One rather similar to the __str__ method is the __repr__ method. Its purpose is to provide a technical representation of the state of the object. We will come across this method later.

Loading
Loading
Loading

Example 2: Task list

The following class TaskList models a list of tasks:

class TaskList:
    def __init__(self):
        self.tasks = []

    def add_task(self, name: str, priority: int):
        self.tasks.append((priority, name))

    def get_next(self):
        self.tasks.sort()
        # The list method pop removes and returns the last item in a list
        task = self.tasks.pop()
        # Return the name of the task (the second item in the tuple)
        return task[1]

    def number_of_tasks(self):
        return len(self.tasks)

    def clear_tasks(self):
        self.tasks = []

The method add_task adds a new task to the list. Each task also has a priority attached, which is used for sorting the tasks. The method get_next removes and returns the task with the highest priority on the list. There is also the number_of_tasks method, which returns the number of tasks on the list, and finally the method clear_tasks, which clears the task list.

Within the object, the tasks are stored in a list. Each task is of a tuple containing the priority of the task and its name. The priority value is stored first, so that when the list is sorted, the task with the highest priority is the last item on the list. This is why we can then simply use the pop method to retrieve and remove the highest priority item.

Please have a look at the following program with the task list in action:

tasks = TaskList()
tasks.add_task("studying", 50)
tasks.add_task("exercise", 60)
tasks.add_task("cleaning", 10)
print(tasks.number_of_tasks())
print(tasks.get_next())
print(tasks.number_of_tasks())
tasks.add_task("date", 100)
print(tasks.number_of_tasks())
print(tasks.get_next())
print(tasks.get_next())
print(tasks.number_of_tasks())
tasks.clear_tasks()
print(tasks.number_of_tasks())
Sample output

3 exercise 2 3 date studying 1 0

Loading

Please respond to a quick questionnaire on this week's materials.

Loading...
:
Loading...

Log in to view the quiz

You have reached the end of this section!

You can check your current points from the blue blob in the bottom-right corner of the page.