Chapter 9
Chapter 9
Programming
Chapter 9
Prepared Mohammed Esmaail Shakfah 1
Spring 2024
06/10/2025
Contents
Object-Oriented Programming
Implementing a Simple Class
Specifying the Public Interface of a Class
Designing the Data Representation
Constructors
Implementing Methods
Testing a Class
Application: Writing a Fraction Class
06/10/2025
Object-Oriented Programming
You have learned structured programming
Breaking tasks into subtasks A class describes objects with the same behavior.
Writing re-usable methods to handle tasks For example, a Car class describes all passenger
We will now study Objects and Classes vehicles that have a certain capacity and shape.
To build larger and more complex programs
To model objects we use in the world
Python Classes
A class describes a set of objects with the same In contrast, the list class describes the
behavior. behavior of objects that can be used to
For example, the str class describes the behavior of store a collection of values
all strings This class has a different set of methods
This class specifies how a string stores its For example, the following call would be
characters, which methods can be used with strings, illegal—the list class has no upper()
and how the methods are implemented. method
For example, when you have a str object, you can
invoke the upper method: ["Hello",
"World"].upper()
"Hello, World".upper()
• However, list has a pop() method,
and the following call is legal
["Hello", "World"].pop()
String Method of class 06/10/2025
object String
Public Interfaces
The set of all methods provided by a class, together with a description of
their behavior, is called the public interface of the class
When you work with an object of a class, you do not know how the object
stores its data, or how the methods are implemented
You need not know how a str object organizes a character sequence, or how a
list stores its elements
All you need to know is the public interface––which methods you can apply,
and what these methods do
06/10/2025
Public Interfaces
In an object-oriented program, objects are asked to carry out the tasks that are
Objects
necessary to achieve a goal.
Methods In order to get an object to carry out a task, you invoke a method on it.
Public Interface The public interface of a class tells you what you can do with objects of the class.
The public interface tells you the "what", not the "how". This gives the implementor
Encapsulation
of the class the freedom to change the implementation.
06/10/2025
Implementing a Simple Class
Example:
Tally Counter: A class that models a mechanical device that is used to count people
For example, to find out how many people attend a concert or board a bus
First, we construct an object of the class (object construction will be covered shortly):
In Python, you don’t explicitly declare instance variables
Instead, when one first assigns a value to an instance variable, the instance variable is created
def click(self) :
self._value = self._value + 1
Class
Methods and Attributes
Note how the click() method increments the instance variable _value
Which instance variable? The one belonging to the object on which the method is invoked
In the example below the call to click() advances the _value variable of the concertCounter object
No argument was provided when the click() method was called even though the definition includes the
self parameter variable
The self parameter variable refers to the object on which the method was invoked concertCounter in
this example
concertCounter.click() 06/10/2025
Example of Encapsulation
The getValue() method returns the current _value:
def getValue(self) :
return self._value
• This method is provided so that users of the Counter class can find out
how many times a particular counter has been clicked
• A class user should not directly access any instance variables
• Restricting access to instance variables is an essential part of
encapsulation
06/10/2025
Complete Simple Class Example
Program execution
06/10/2025
Example
1. Lines 11, 12, and 13 execute. The next line
executed after line 13 is line _____.
2. Next, line 3 executes. What is the value of
tally._value?
3. The next line executed after line 3 is line _____.
4. The next line executed is line _____.
5. Next, line 6 executes. What is the new value of
tally._value?
6. The next line executed after line 6 is line _____.
7. The next line executed is line _____.
8. Next, line 6 executes. What is the new value of
tally._value?
9. The next line executed after line 6 is line _____.
10. The next line executed is line _____.
11. Next, line 9 executes. The execution flow returns
to line 16 in the main function. What is the value of 06/10/2025 12
result?
Public Interface of a Class
When you design a class, start by specifying the public interface of the new class
What tasks will this class perform?
What methods will you need?
What parameters will the methods need to receive?
06/10/2025
Writing the Public Interface
## A simulated cash register that tracks the item count and the total
amount due.
#
Class comments document
class CashRegister :
the class and the behavior
## Adds an item to this cash register.
of each method
# @param price: the price of this item
#
The method declarations make
def addItem(self, price) :
up the public interface of the
# Method body
class
06/10/2025
Using the Class
After defining the class we can now construct an object:
register1 = CashRegister()
# Constructs a CashRegister object
• This statement defines the register1 variable and initializes it with a reference to a new
CashRegister object
06/10/2025
Accessor and Mutator Methods
Many methods fall into two categories:
1) Accessor Methods: 'get' methods
Asks the object for information without changing it
Normally returns the current value of an attribute
def getTotal(self):
def getCount(self):
06/10/2025
Instance Variables of
Objects
Each object of a class has a separate set of instance variables
06/10/2025
Designing the Data Representation
An object stores data in instance variables
Variables declared inside the class
All methods inside the class have access to them
Can change or access them
What data will our CashRegister methods need?
Task Method Data Needed
Add the price of an item addItem(price) total, count
06/10/2025
Example
Consider the following code segment.
class Date :
...
def getMonth(self) :
return self._month
def getDay(self) :
return self._day
...
1. Assuming that object birthday is an instance of the Date class, which is a correct
way to call the getMonth method?
06/10/2025 19
Example
1. Lines 1 through 5 execute. What is the value of
count?
2. Next, lines 6 and 7 execute. What is the value of
total?
3. Next, line 8 executes. What is the new value of
count
4. Next, lines 9 and 10 execute. What is the new
value of total?
06/10/2025 20
Example
Classify the following methods as either an accessor or a mutator.
1. The addItem method of the CashRegister class.
2. The getTotal method of the CashRegister class.
3. The clear method of the CashRegister class.
4. The click method of the Counter class.
5. The getValue method of the Counter class.
6. The pop method of the list class.
7. The upper method of the str class.
8. What is the name of the instance variable in the following code segment?
class Fruit :
def getColor(self) :
return self._color
06/10/2025 21
Programming Tip 9.1
All instance variables should be private and most methods should be public
Although most object-oriented languages provide a mechanism to explicitly hide
or protect private members from outside access, Python does not
It is common practice among Python programmers to use names that begin
with a single underscore for private instance variables and methods
The single underscore serves as a flag to the class user that those members are
private
You should always use encapsulation, in which all instance variables are
private and are only manipulated with methods
Typically, methods are public
However, sometimes you have a method that is used only as a helper method by
other methods
In that case, you should identify the helper method as private by using a name
that begins with a single underscore 06/10/2025
06/10/2025 23
Constructors Only one constructor can be defined per class
A constructor is a method that
But you can a define constructor with default
initializes instance variables of an
argument values that simulate multiple
object
It is automatically called when an object definitions
is created
class BankAccount :
# Calling a method that matches the
def __init__(self, initialBalance =
name of the class
0.0) :
# invokes the constructor
self._balance
• If no value = initialBalance
is passed to the constructor when a
register = CashRegister()
BankAccount object is created the default value will be
• Python uses the special name _ _init_ _ used
for the constructor because its purpose is joesAccount = BankAccount() # Balance is set
to initialize an instance of the class: to 0
If a value is passed to the constructor that value
will be used instead of the default one
def _ _init_ _(self) :
self._itemCount = 0
joesAccount = BankAccount(499.95) # Balance
self._totalPrice = 0
is set to 499.95
• Default arguments can be used in any method
and not just constructors
06/10/2025
Syntax: Constructors
06/10/2025
Constructors: Self
The first parameter variable of every constructor must be self
When the constructor is invoked to construct a new object, the self
parameter variable is set to the object that is being initialized
Refers to the
object being
initialized
def _ _init_ _(self) :
self._itemCount = 0
self._totalPrice = 0
register = CashRegister()
print("Your total $",
register.getTotal())
In general, you should never call a Python method that starts with a
double underscore. The are intended for specific internal purposes
(in this case, to initialize a newly created object).
After an object has been constructed, you should not directly call the
constructor on that object again:
register1 = CashRegister()
register1._ _init_ _() # Bad style
06/10/2025
Example
class Date :
def __init__(self) :
self._month = 1
self._day = 1
self._year = 2000
## Mutator method to change the value of instance variable day.
def setDay(self, newDay) :
## Accessor to retrieve the value of instance variable day.
def getDay(self) :
1. Assuming that methods setDay and getDay are implemented correctly, what is
the output from the following code segment?
birthday = Date()
yesterday = Date()
birthday.setDay(15)
print(birthday.getDay(), yesterday.getDay()) 06/10/2025 28
06/10/2025 29
Implementing Methods
Implementing a method is very similar to implementing a function except that you access
the instance variables of the object in the method body
def addItem(self, price):
self._itemCount = self._itemCount + 1
self._totalPrice = self._totalPrice + price
Task Method
Add the price of an item addItem(price)
06/10/2025
Invoking Instance Methods
As with the constructor, every method must include the special self
parameter variable, and it must be listed first.
When a method is called, a reference to the object on which the method
was invoked (register1) is automatically passed to the self parameter
variable:
register1.addItem(2.95)
register1.addItems(6, 0.95)
06/10/2025
Example: CashRegister.py (1)
06/10/2025
Programming Tip 9.2
Instance variables should only be defined in the constructor
All variables, including instance variables, are created at run time
There is nothing to prevent you from creating instance variables in any method of a class
The constructor is invoked before any method can be called, so any instance variables that were created in
the constructor are sure to be available in all methods
06/10/2025
06/10/2025 36
Testing a Class
In the long run, your class may become a part of a larger program that interacts with
users, stores data in files, and so on
You should always test your class in isolation integrating a class into a program
Testing in isolation, outside a complete program, is called unit testing
As your classes get more complex, you should write tester programs
A tester program is a driver module that imports the class and contains statements to run methods
of your class
06/10/2025
Example Test Program Program execution
We want to use our rational numbers as we would use integers and floating point values
Thus, our Fraction class must perform the following operations:
1. Create a rational number
2. Access the numerator and denominator values, individually
3. Determine if the rational number is negative or zero
4. Perform normal mathematical operations on two rational numbers (addition, subtraction,
multiplication, division, exponentiation)
5. Logically compare two rational numbers
6. Produce a string representation of the rational number
The objects of the Fraction class will be immutable because none of the operations
06/10/2025modify
the objects’ instance variables
Required Data Attributes
Because a rational number consists of two integers, we need two instance variables to
store those values:
self._numerator = 0
self._denominator = 1
• At no time should the rational number be converted to a floating-point value or we will lose
the precision gained from working with rational numbers
Signed values
Negative and positive rational numbers each have two forms that can be used to specify the
corresponding value
Positive values can be indicated as 1/2 or –1/–2, and negative values as –2/5 or 2/–5
When performing an arithmetic operation or logically comparing two rational numbers, it will be
much easier if we have a single way to represent a negative value
For simplicity, we choose to set only the numerator to a negative value when the rational number
is negative, and both the numerator and denominator will be positive integers when the rational
number is positive
06/10/2025
Representing Values Equivalently
Equivalent fractions
For example, 1/4 can be written as 1/4, 2/8, 16/64, or 123/492
It will be much easier to perform the operation if the number is stored in reduced
form
06/10/2025
The Constructor
def _ _init_ _(self, numerator = 0, denominator =
1) :
if denominator == 0 :
raise ZeroDivisionError("Denominator
cannot be zero.")
if numerator == 0 :
self._numerator = 0
self._denominator = 1
else :
if (numerator < 0 and denominator >= 0 or
numerator >= 0 and denominator < 0) :
sign = -1
else : frac1 = Fraction(1, 8) # Stored as 1/8
sign = 1
a = abs(numerator) frac2 = Fraction(-2, -4) # Stored as 1/2
b = abs(denominator) frac3 = Fraction(-2, 4) # Stored as -1/2
while a % b != 0 : frac4 = Fraction(3, -7) # Stored as -3/7
tempA = a frac5 = Fraction(0, 15) # Stored as 0/1
tempB = b frac6 = Fraction(8, 0) # Error! exception is
a = tempB raised.
b = tempA % tempB
self._numerator = abs(numerator) // b * 06/10/2025
sign
Comparing Fractions (1)
In Python, we can define and implement methods that will be called
automatically when a standard Python operator (+, *, ==, <) is applied to an
instance of the class
For example, to test whether two fractions are equal, we could implement a
method:
isequal() and use it as follows:
if frac1.isequal(frac2) :
print("The fractions are equal.")
06/10/2025
Comparing Fractions (2)
• Of course, we would prefer to use the operator ==
• This is achieved by defining the special method:
_ _eq_ _():
06/10/2025
Special Methods
• Some special methods are called when an instance of
the class is passed to a built-in function. For example,
suppose you attempt to convert a Fraction object to a
floating point number using the float() function:
x = float(frac1)
Then the _ _float_ _() special method is called.
Here is a definition of that method:
06/10/2025
Common Special Methods
06/10/2025
Common Special Methods
06/10/2025
Addition of Fractions
All of the arithmetic operations that can be performed on a Fraction object
should return the result in a new Fraction object
For example, when the statement below is executed, frac1 should be
added to frac2 and the result returned as a new Fraction object that is
assigned to the newFrac variable
06/10/2025
Fractional Addition
From elementary arithmetic, you know that two fractions must have a
common denominator in order to add them. If they do not have a common
denominator, we can still add them using the formula:
06/10/2025
Defining the Method For Addition
06/10/2025
Logic: Less Than
Note that a / b < c / d when d · a < b · c. (Multiply both sides with b · d.)
Based on this observation, the less than operation is implemented by the _
_lt_ _() method as follows:
def _ _lt_ _(self, rhsValue) :
return (self._numerator *
rhsValue._denominator
self._denominator *
rhsValue._numerator)
06/10/2025
Fraction.py
06/10/2025
06/10/2025
06/10/2025
06/10/2025
Checking Type
To ensure that, Python provides the built-in isinstance() function that can
be used to check the type of object referenced by a variable.
For example, the constructor for the Fraction class requires two integers
class Fraction :
def _ _init_ _(self, numerator, denominator) :
if (not isinstance(numerator, int) or
not isinstance(denominator, int)) :
raise TypeError
("The numerator and denominator must be
integers.")
06/10/2025