Está en la página 1de 12

Defining Classes

We have covered built-in data types in Python, namely


int 12, –12
float 1.2, –25.5
bool True, False
str 'James', '15', "one" (Note that both single quote, and double quote can be used to
embed characters in string)

We have also learned how to manipulate these data types using:


Operators:
Arithmetic Relational (Comparison) Logical
+ 5 + 2  7 == 5 == 2  False and True and False  False
– 5 – 2  3 != 5 != 2  True or True or False  True
* 5 * 2  10 > 5 > 2  True not not True  False
/ 5 / 2  2.5 >= 5 >= 2  True
// 5 // 2  2 < 5 < 2  False
% 5 % 2  1 <= 5 <= 2  False
** 5 ** 2  25

Functions Methods (mainly on the data type str)


max(5, 3)  5 'James'.center(10)  ' james '
min(–5, 3)  –5 'James Bond 007'.count('0')  2
abs( –5.5)  5.5 'James Bond 007'.count('A')  0 (Not found)
abs(5.5)  5.5 'James Bond'.find('me')  2
len('James')  5 'James Bond'.find('mee')  –1 (Not found)
ord('A')  65 'January'.replace('a','i')  'Jinuiry'
chr(65)  'A' 'James Bond 007'.split()
str(65)  '65'  ['James', 'Bond', '007']
int(65.5)  65 'January'.split('a')  ['J', 'nu', 'ry']
int('65')  65 'James'.upper()  'JAMES'
float('65')  65.0
float(65)  65.0
We have also learned how to control the flow of Python statements/scripts using:
Selection
if if num > 0: Only if num > 0 is true (e.g.
print(math.sqrt(num)) num is 10) will the square
root of num be printed, if
num > 0 is false (e.g. num is
-16), then there is no output.
That is only if the condition
is true, there is output.

if-else if num >= 0 and num <= 100: If num >= 0 and num <= 100
print('Valid mark') is true, then display Valid
else: mark, but if it is false, then
print('Invalid mark') Invalid mark is display. That
is, whether the condition is
true or false, there is output

if-elif if 0 <= qty <= 50: If qty is not between 0 and


print('Discount is', 0.05) 100, inclusive, then there is
elif 50 < qty <= 100: no output, as there is no
print('Discount is', 0.1) ‘else’ part for false condition.

and … (next page please)


Repetition/Iteration (loop)
for for i in range(3): Initialisation, 0
print(i) Testing, and 1
Update 2
all in ONE line!
for ch in 'James': J
print(ch) a
m
e
S

for word in 'James Bood 007'.split(): James


print(word) Bond
007

sum = 0
for i in range(1,6):
sum += i
print('Sum =', sum) Sum = 15

while As counter-controlled loop:


count = 1 Initialise counter
sum = 0
while count <= 5:
sum += count Testing counter
count += 1 Sum = 15
Update counter
print('Sum =', sum)

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)

Enter name (<Enter> to quit): James


Enter name (<Enter> to quit): Jimmy
Enter name (<Enter> to quit): Jane
Enter name (<Enter> to quit):
You have entered 3 name(s)
Of course, we have also learned how to break up complex program into smaller,
manageable tasks, which are coded into functions:
Functions

A function definition
 begins with the keyword 'def',
 followed by the function name,
 parameter list, and
 function body

def greeting(name, gender): A function that accepts two parameters,


if gender.lower() == 'f': name, and gender, both are of type str. The
print('Hello, Ms.', name) method does not return anything, but just
elif gender.lower() == 'm': display the greeting title ‘Ms’ or ‘Mr.’
print('Hello, Mr.', name)
else:
depending on the gender. If invalid gender,
print('Hello,', name) no greeting title is displayed.

def isValid(mark): A function that accepts a mark of type float,


return 0 <= mark <= 100 and determines whether the mark represents a
valid exam mark. A valid mark is between 0
and 100, inclusive.

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?…

Defining you own data type….

Defining classes to represent your own data type …

Using your own defined classes to create objects that


interact with each other in your programs…
Let’s say, we want to write Python program to manipulate a collection of books in a library or
in a bookshop. Information about a book includes title, author, publisher, year published,
price, ISBN, and many more. We have to consider which of this information is relevant to the
problems that we are trying to solve. For the purpose of this discussion, the information that
we would like to keep track about a book are: title, author, year published, and price.

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()

Then initialise each of its attributes with


actual values.

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).

Though we cannot display the detail information about the Book


object as the compiler does not have any prior knowledge of a
book, but we do can display the fields’ (or attributes’) value as
they are built-in data type, and Python compiler do know how to
display them when used in a print statement. But we need four
(4) print statements to display the detail of a Book object, won’t
it be nice to just use a single print line to display the detail
information about the Book object?
(Yes, the __str__ method again!)
Disadvantage of creating object using default constructor:
Here you need five (5) statements just to create a Book object – first use the default
contractor to create an instance of Book, next we use one statement each for its
attribute. Imagine if we were to have 10 attributes, then it needs 11 statements!

Solution: Create our own constructor with arguments!

Creating our own constructor with arguments (or parameters):


The first parameter of a
method is always named
self, which is a reference
to the object on which the
method is acting.
The next four parameters
will be the place holders
for the actual values that
we are passing in when we
invoke this constructor
Using constructor with arguments method
The method body consists
of statements that initialise
the Book’s attributes
(syntax: with self follow
by the dot operator) with
the parametric values

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.

Check for duplicate – using


__eq__ method
Sorting objects
Occasionally, when we store Book objects in a list, we would like to see the books sorted in
some specific order, say, according to the price.

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 obejects, 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 critieria 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.

The next page shows the full source code for the class Book.
class Book:
"fields: title, author, year, price"

# constructor with arguments


def __init__(self, title, author, year, price):
self.title = title
self.author = author
self.year = year
self.price = price

# returns details of Book object as a string


def __str__(self):
return "{0} ({1}) by {2} costs {3:1.2f}".format( \
self.title, self.year, self.author, self.price)

# setter methods
def setTitle(self, newTitle):
self.title = newTitle

def setAuthor(self, newAuthor):


self.author = newAuthor

def setYear(self, newYear):


self.year = newYear

def setPrice(self, newPrice):


self.price = newPrice

# 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

# test for equality, only 3 attributes are used here: title,


# author, year
def __eq__(self, other):
return self.getTitle().upper() == other.getTitle().upper() and \
self.getAuthor().upper() == other.getAuthor().upper() and \
self.getYear() == other.getYear()

# these methods are for sortiong


def __lt__(self, other):
return self.getPrice() < other.getPrice()

def __le__(self, other):


return self.getPrice() <= other.getPrice()

También podría gustarte