ICS4U – Introduction to Object Oriented Programming in Python

ICS4U Learning Goals

In this ICS4U Grade 12 Computer Science lesson you will be learning how to

  • Create classes to define objects
  • Create instances of objects to solve problems

Objects

Games are often a good way to think about how to use objects inside a program. Take the game pacman.

ICS4U Pacman Objects Lesson

In pacman, you might consider the following as objects that exist in the game

  • Pacman
  • Ghosts
  • Point Dots
  • Power Ups
  • Walls

Objects generally store information about itself. This information (data) is called the objects instance attributes

Objects often have behaviours they they would execute when something happens. These behaviours (functions) are called instance methods

Example Pacman Object

You could consider pacman to be a new custom data type

Attributes:

  • x position
  • y position
  • speed
  • direction
  • image
  • lives

Behaviours:

  • Move in any of 4 directions
  • Eat Ghost
  • Eat Dot
  • Die

Example Fraction Object

Suppose you wanted to create a new data type to represent a rational number

Attributes:

  • Numerator
  • Denominator

Behaviours

  • Add, Subtract, Multiply, Divide
  • Convert to Decimal equivalent
  • Convert to Mixed Fraction
  • Convert to lowest terms
  • Display in form n/d

Example Phone Book Object

Suppose you wanted to make a new data type to represent a phone book

Attributes:

  • First Name
  • Last Name
  • Phone #
  • Address

Behaviours

  • Add or Delete Person
  • Change info
  • LookUp Info
  • Sort Information
  • Display Information

The concept of combining data and functions into classes is called Encapsulation

Classes

When you create program you will create templates for objects. In Object Oriented Programming, these templates are called Classes. A Class defines the attributes and behaviours for an object. When you add an object into your program it is known as an instance of that Class. The main point is that a single Class can create many instances of an object in your program. For example, in Pacman it is not necessary to create a different Class for each individual point object wish to display on the screen. You define 1 Class for the Point Dot and create many instances of that object in the game. The same would apply to a Ghost Objects Each instance of a particular object will have the same attributes as every other instance of that particular object, but the values of those attributes will be different for each instance Blinky Ghost (The Red One) might be at grid space (3,4) moving at 5 pixels/tick
  • xPosition = 3
  • yPosition = 4
  • speed = 5
  • color = “Red”
Clyde Ghost (The Orange One) might be at grid space (10,3) moving at 7 pixels/tick
  • xPosition = 10
  • yPosition = 3
  • speed = 7
  • color = “Orange”

Structure of a Python Class

Instance Variables are represented by variables in your Class. They are sometimes called Fields as well

Behaviours are represented by functions in your Class.

There are different types of functions that “might” be contained inside your Class.

Constructors

  • These define how a programmer can create the object from the main program
  • They usually set the value of the attributes to some initial value

Accessor and Mutator Functions

  • Accessors retrieve the information stored in the attributes (Sometimes they are called “getters”)
  • Mutators modify the information stored in the attributes (Sometimes they are called “setters”)
  • Some languages like Java use these more so that Python, since there are easier ways with python to access this data

Behaviour Functions

  • Carry out the required behaviour for the object

Helper Functions

  • Background functions that assist in carrying out the behaviours
  • Some other programming languages consider theses private functions.  Not meant to be used by the instances themselves within the main program.  

The values that each instance attribute has at any point in the program are known as the state of the instance

Summary

Example - Bank Account Program

This example is going to look at how to use an object to solve a problem involving a Bank

The Problem You are trying to Solve

You have been given a task by a Bank to help write some software to create bank accounts for their customers. The bank needs to be able to create accounts with the customers name and an initial balance. Bank employees will need to be able to deposit money into the account, withdraw money from the account, and display the current balance of the account.

The Design of the Class

Attributes: What data needs to be stored for each object

  • A variable to store the name of owner of the account (should be a String data type)
  • A variable to store the amount of money in the account (should be a float data type)

Constructor: What should happen when the object first gets created?

  • Need to set the name of the account holder and the initial balance in the account
  • Should only allow positive amounts of money to be created

Behaviours: What should each object be able to do?

  • Deposit Function:
    • No Return Value
    • Accepts a value to represent the amount of deposit
    • Add the deposit to the existing balance
    • Check for a negative input
  • Withdraw Function:
    • No Return Value
    • Accept a value to represent the amount of deposit
    • Subtract the deposit from teh existing balance
    • Chec for negative input and if there is enough money in the account
  • Display Function:
    • Return a String representing the owners name followed by the account balance
    • No parameters need to be passed to the function

Programming a Class in Python

Classes are defined a lot like functions, and should be at the top of your main program area. You need to give the class a name. The name should start with an Uppercase letter and be representative of the object you are trying to create. All attributes and functions definitions are indented to indicate they belong to that particular class

				
					class Name:

	#Constructor

	#Behaviour Methods


#Main Program Would start down Here
def main():
    
    #Solve a problem

main()
				
			

Creating the Constructor

Constructor methods are defined as follows using the __init__ function.

  • The __ are two underscore keys.
  • A parameter list of values to send to the function come next, but you also pass the keyword self to the constructor.
  • When the object is created it passes the name of itself to its constructor so it knows what instance to execute the behaviours for
				
					
class Account:

	#Constructor
	def __init__(self,owner,balance):

		#Set the owner
		self.owner = owner

		#Check for positive Balance and Set it
		if balance >= 0:
			self.balance = balance
		else:
			print("Invalid Balance: Default to Balance of Zero")
			self.balance = 0
				
			

Notice how you are using the keyword self whenever you access the instance variable inside a Class.

  • The Scope of these instance variables are global for the class, but local for the entire program.
  • You can use them in any function within the class

It doesn’t matter that you are using the same variable name in the parameter list as in the instance variable. They would be treated as separate variables as long as the keyword self is being used.

If you don’t use the keyword self with your variables, then those variable values would apply to EVERY instance you create of the object, and not just the instance you create

Writing The Behaviour Functions

These functions would be written just like all other functions you have been using so far…. But you must also pass self into the function first.

This might be what the entire Bank Account Class might look like for this problem

				
					
class Account:

	#Constructor
	def __init__(self,owner,balance):
		self.owner = owner
		if balance >= 0:
			self.balance = balance
		else:
			print("Invalid Balance: Default to Balance of Zero")
			self.balance = 0

	#Behaviour Methods
	def deposit(self, amount):
		if amount > 0:
			self.balance = self.balance + amount
		else:
			print("Error: Positive Deposit Required")

	def withdraw(self, amount):
		if amount > 0:
			if amount <= self.balance:
				self.balance = self.balance - amount
			else:
				print("Error: You didn't have that much")
		else:
			print("Error: Positive Withdrawal Required")

	def display(self):
		return "Owner: " + self.owner + "\nBalance: $" + str(self.balance) +"\n"
				
			

Using the Class

Now that you have defined the class we can create objects in the main part of our program.

You should notice that

  • To create an object you use a function with the same name as the class and pass the correct arguments to it.
  • You assign the object to a variable just like any other piece of data.
  • Behaviour methods are called using that variable name. Notice the dot notation of variable.function()

You can create as many Accounts as you want and modify them easily using a single Class definition

The self keyword is really what makes this possible, because it only modifies the variables stored in the correct memory location for each object

				
					
def main():
    
    # Creating new account object using the constructor
    a1 = Account("Paul Rogers", 1000)
    a2 = Account("Ace Ventura", 4000)
    
    # Using the Behaviour Methods
    a1.withdraw(300)
    a2.withdraw(500)
    a1.deposit(1000)
    a2.deposit(6000)

    # Show account status
    print(a1.display())
    print(a2.display())

main()
				
			

Printing Objects

We created a Display function to display all of the information that we the user to have. It would be nice if we could just use the variable name, like printing a regular variable. If you try to do that right now then all you will get is the memory location

If you include a  __str__ function in your class then you can just use the object name when printing.

  • It has to return a string, and your program will display the value of that string in a print statement. You can customize to be whatever you want it to be. 
				
					
def __str__(self):
		return "Owner: " + self.owner + "\nBalance: $" + str(self.balance) +"\n"
				
			
				
					
def main():
    
    # Creating new account object using the constructor
    a1 = Account("Paul Rogers", 1000)

    # Show account status
    print(a1)

main()
				
			

Accessing Values of Instance Variables

Just as we access the behaviour functions using the dot notation, you can access the instance variables using the dot notation as well. Here is a main program that reads and modifies the field variables from an account

				
					
def main():
    # Creating new account object using the constructor
    a1 = Account("Paul Rogers", 1000)
    a2 = Account("Ace Ventura", 6000)

    #Display the values of some instance varaibles called owner and balance
    print(a1.owner)
    print(a2.balance)
    
    #Modify instance variables
    a1.balance = 20000
				
			

ICS4U Coding Questions

Try to code the following questions using an IDE of your choice.  You will save those files on your computer for future reference. 

Each question has:

  • A video of your teacher live coding and explaining the solution
  • The final code used in the video.

Try your best to solve the problems yourself without looking at the solutions.

Make sure you test your programs with multiple different inputs to ensure it is functioning properly.

Treat these questions like Math homework (Do as many as you feel you need to do to feel comfortable with the material)

ICS4U Practice Question

Name Your File:  “ICS4UcircleObject.py” 

Create a Class to represent a Circle with the following information

Attributes:

  • Radius (a floating point number)

 Constructor:

  • Accept the radius as a parameter

Behaviours:

  • getArea -> returns the area of the circle
  • getCircumference -> returns the circumference of the circle

Write a main program that tests your class.

  • Create a few Circle objects with different radius values and then call the behaviour functions to see if they are working correctly.

				
					
class Circle:

    #Constructor
    def __init__(self,radius):
        self.radius = radius


    #Behaviours
    def getArea(self):
        return 3.14*self.radius**2

    def getCircumference(self):
        return 2*3.14*self.radius


def main():

    #Make a circle of radius 5
    c1 = Circle(5)
    print(c1.getArea())
    print(c1.getCircumference())

    #Make a circle of radius 1
    c2 = Circle(1)
    print(c2.getArea())
    print(c2.getCircumference())

main()
				
			

ICS4U Practice Question

Name Your File:  “ICS4UgeometricCircleObject.py” 

Create a Class to represent a Circle with the following information

Attributes:

  • Radius (a floating point number)
  • CenterX (an int)
  • CenterY (an int)

 Constructor:

  • Accepts 4 integer points on the Cartesian Grid
  • Center (x,y) and another point on the circle (x,y)
  • Assign a value to the radius based on the inputs, use a helper function

Behaviours:

  • getArea -> returns the area of the circle
  • getCircumference -> returns the circumference of the circle
  • __str__ -> Display the attributes

Write a main program that tests your class.

  • Create a few Circle objects with data points from a file and then call the behaviour functions to see if they are working correctly.

				
					
import math

class Circle:

    #Constructor
    def __init__(self,cx,cy,px,py):
        self.cx = cx
        self.cy = cy
        self.radius = self.findRadius(px,py)

    #Behaviours
    def getArea(self):
        return 3.14*self.radius**2

    def getCircumference(self):
        return 2*3.14*self.radius

    def __str__(self):
        return "Circle Center: ("+str(self.cx)+","+str(self.cy)+"), radius = "+ str(self.radius)

    #Helper
    def findRadius(self,px,py):
        return math.sqrt((self.cx-px)**2 + (self.cy-py)**2)

def main():

    #Data contained in the file
    file = open("data.txt", "r")

    #10 pieces of data in the data file
    for i in range(0,10):

        #Read the comma delimited data file: cx,cy,px,py
        data = file.readline().split(",")

        #Make a new circle and output the info
        c = Circle(int(data[0]),int(data[1]),int(data[2]),int(data[3]))
        print(c)
        print("Area: ", c.getArea())
        print("Circumference: ", c.getCircumference())

main()
				
			

ICS4U Practice Question

Name Your File:  “ICS4UgamePlayer.py” 

You are making a game where a  player spins a wheel and rolls a dice to earn points.  Create the player with the following properties:

Attributes:

  • Points (total points won during the game)

 Constructor:

  • No input parameters needed, just set the points to zero

Behaviours:

  • spin -> simulates spinning a disk with different colors.  60% of the disk is Blue and earns 3 points, 25% of the disk is Yellow and earns 5 points, 10% of the disk is Red and earns 8 points, 5% of the disk is Black and earns 0 points.  Returns the number of points
  • roll -> simulates rolling a 6 sided dice, returns the points earned which is equal to the roll of the dice

Write a main program that tests your class.

  • Make 2 players.  Each round of the game consists of a spin and a roll.  Display the winner after 20 rounds.  

				
					
import random

class Player:

    #Constructor
    def __init__(self):
        self.points = 0

    def spin(self):
        val = random.randint(1,100)

        if val >= 1 and val <= 60: #Blue
            self.points = self.points + 3
            return 3
        elif val > 60 and val <= 85: #Yellow
            self.points = self.points + 5
            return 5
        elif val > 85 and val <= 95: #Red
            self.points = self.points + 8
            return 8
        else:
            return 0


    def roll(self):
        val = random.randint(1,6)
        self.points = self.points + val
        return val

def main():
    p1 = Player()
    p2 = Player()

    for i in range(0,20):


        s = p1.spin()
        r = p1.roll()
        t = s + r
        print("P1: earned", t, "Points")

        s = p2.spin()
        r = p2.roll()
        t = s + r
        print("P2: earned", t, "Points")

    print("Game Over: ")
    print("P1 Total: ", p1.points)
    print("P2 Total: ", p2.points)

    if p1.points > p2.points:
        print("P1 Wins")
    elif p2.points > p1.points:
        print("P2 Wins")
    else:
        print("Tie Game")


main()