Defining Own Classes
Defining Own Classes
sum = 0
for i in range(1,6):
sum += i
print('Sum =', sum) Sum = 15
Priming read
As sentinel-controlled loop: (Initialisation)
name = input('Enter name (<Enter> to quit): ') Testing for sentinel
count = 0
while name != '': Follow-up read
count += 1 (Update)
name = input('Enter name (<Enter> to quit): ')
print('You have entered', count, 'name(s)')
Sample runs:
Enter name (<Enter> to quit):
You have entered 0 name(s)
A function definition
• begins with the keyword 'def',
• followed by the function name,
• parameter list, and
• function body
So far, all data types that we dealt with are built-in, and mostly atomic data (i.e. they only
consist of single piece of information, such as 15 (int), True (bool)). The problems that we
are trying to solve may contain structure/complex data, and there may not have any
equivalent data types available in Python. For example, we may need to process information
about students, employees, cars, books, items, etc. – which are made up of multiple pieces of
information. For example, a student has name (of type str), age (of type int), height and
weight (both are of type float), whether he/she has paid fee (of type bool), etc. If we were to
represent this related information, we need five (5!) variables. If we are representing two
students, then we had to use a total of ten (10) variables – name1, age1, height1, weight1,
hasPaid1 for student number 1, and name2, age2, height2, weight2, hasPaid2 for student
number 2. Now, what if we have 100 students! Imagine the number of variables that we need.
…. Solution?…
To create a class called Book to represent a book, we start with the header class Book, as
shown below:
Saved your file as library.py
That is it. It is simple. Now we have
a new data type called Book that
can hold more than one piece of
information
Click Run > Run Module (or Press F5) to start using the data type you have just define.
In the Python Shell, you may create a variable to reference a Book object, using the default
constructor Book().
When you type the (, you will see that Python display the attributes of a book, as shown
above.
Once you have created a book, you need to initialise its attribute with some actual
information:
Create a Book object using default (no-
arguments) constructor: Book()
When we print the Book object reference by b, the output <__main__.Book object at
0x00C43610> shows that b is referencing a Book object at the memory address 0x00C43610.
(0x means the number is in hexadecimal). The actual values of each attributes are not shown.
We need to define our own method to tell the compiler what to display when we use print
statement (More about this later: the __str__ method).
Now we can create a Book object with only one (1!) statement.
But the printing of the Book object still display that it is referencing a Book object at another
memory address.
NOTE: Once you have created your own constructor with arguments, the default
constructor is NOT available any more. Using it will result in compiled error.
So if you still want to have the default constructor, then you must define it in the class.
__str__ method
Now it is time to write a method that will return the detail information about a Book object as
a string, concatenating all its attributes as string. We want the information to be in the format:
<title> (<year>) by <author> costs <price>
e.g. Basic Java (2010) by Me costs 12.00
The required method is called __str__. Note: There are TWO underscores between the
word str.
We use string formatter to format the returned string, with the floating-point price set to 2
decimal places.
Now that we have defined the __str__ method that will be used by Python to display a Book
object’s detail, invoking the print statement on a Book object will automatically use this
__str__ method to return the formatted string.
Setter/Mutator methods
Next we would like to have some methods that will allow us to change/modify the attributes’
value of a Book object. These methods are called setter/mutator methods.
For every attribute, we will write a setter method that will allow us to modify its values in
client code.
Getter/Accessor methods
For every attribute, we would write a getter/accessor method that will allow us to
retrieve/access its value in client code. Note: We do can access the attribute’s value directly
as shown in the previous code fragment, but it is not appropriate in an Object-Oriented
approach.
In our program, we do want to compare whether two Book objects are equal or not, so that
we will not store duplicate copy in a list.
Look at the following program fragment. Python do know how to compare equality of two
integer numbers, but when we try to compare to Books object, b3 and b4 – but surprisingly,
the result is False, even though ALL the fields have the same values! Same goes for checking
whether the book referenced by b3 is in the book list, lob – the answer is No (False).
???
???
We are building our own data type, Python does not know about our attributes, and thus has
no idea what criteria to use for checking equality of Book objects. Another difficulty is two
people may have used two different criteria for checking equality of books. One may use only
title and author for checking equality, whereas another may use title, author, and year
published as criteria for checking equality. So as the class creator/designer, we need to define
our own method for checking equality.
__eq__ method
In this example, I have choose three attributes for checking equality of Book objects, namely
title, author, and year published.
With this method, Python now know how to compare Book objects for equality, as shown
below:
As we only used three attributes as the criteria for checking equality – that’s why b3 == b5 is
true, even though their price differ. This is because price is not a criterion used in checking
for equality.
So we can use the in operator to check for whether we have duplicate object to be added to
the list, and we can use remove(obj) method to remove a Book object from a list of books.
In Python, the list has a method sort that will sort the objects in a list, according to some
specific order. The method sort mutate the list, i.e. after calling the sort method, the data in
the list will be sorted, and not in its original order that you have inserted them. If you just
want to see the elements in the list being sorted, but you do NOT want to mutate the list, then
you should use the function sorted, with the list passed as parameter:
Assuming that intList is a list of integers, then
invoking sort method on it, intList.sort(), will mutate the elements in the list – the
elements will be sorted in ascending. But if instead you use the function,
sorted(intList), then what this function do is return a copy of the original elements,
sorted according to some criteria. The original order is not changed.
But when we invoke sorted on a list of Book objects, we will get run-time error, stating that
our Book object is not orderable:
Again, Python does not know how to order (sort) your own defined data type – class Book!
For this subject, for simplicity, if you want to sort you list of objects, you need to implement
the following methods:
__lt__(obj)
__le__(obj)
[Note: In actual fact, implementing the __lt__(obj) method is suffice for storing, as pointed
out in Python documentation]
We would like to sort a collection of Books according to the price. So we need to implement
the less than, and less than or equal methods.
Now, we have defined our own criteria of what does it mean by a Book object is less than (or
less than or equal to) another Book object, the sorting of a list of Books now working
correctly.
Occasionally we would like to sort the list according to different criteria (attribute) such as
sorting the list according to the author’s name or year published. The function sorted allows
us to pass in a second parameter, which represent the sorting criteria. Examples are shown on
next page.
The next 2 page shows the full source code for the class Book.
The last page will be the PREFERRED version. The one that hides the names of all
attributes.
class Book:
"fields: title, author, year, price"
# setter methods
def setTitle(self, newTitle):
self.title = newTitle
# getter methods
def getTitle(self):
return self.title
def getAuthor(self):
return self.author
def getYear(self):
return self.year
def getPrice(self):
return self.price
class Book:
'fields: title, author, year, price'
# getter methods
def getTitle(self):
return self.__title
def getAuthor(self):
return self.__author
def getYear(self):
return self.__year
def getPrice(self):
return self.__price
# setter methods
def setTitle(self, newTitle):
self.__title = newTitle
def __str__(self):
return '{} ({}) by {}, costs {:0.2f}'.format(self.__title,
self.__year,
self.__author,
self.__price)