CISC-121
20130301
Classes and Objects continued
We completed our brief introduction to Classes and Objects in Python.
Importing Class Definitions
One
of the big advantages of Object Oriented Programming is that it lets us
define all aspects of our new data type in one place - then we can
simply copy the definitions into any program where we want to create
and manipulate objects of that type. The problem with that is if
we ever want to change the definition of a class (say, add another
attribute or change the working of a function) then for consistency we
should edit every program where the definition is included.
Python gives us a much cleaner way to do this: use the import command that we are already familiar with.
Suppose we have created a Date
class (see the accompanying Python file Date.py). Then if we want
to be able to use Date objects in another program, we can put "from Date import *"
at the top of the program (see the accompanying Python file Book.py).
Note that Date.py should be in the same directory as the program
doing the importing, or in one of the directories that Python
automatically searches when importing - in this course we will just put
our class definitions in the same directory as our programs.
This means that if we need to change or add to the definition of the Date class, we only have to do it in one place.
The __init__ function
The __init__
function is used to establish the attributes of each new object created
in the class, typically by means of parameters with default values.
The Date class contains a typical __init__ :
def __init__(self,
year = 0,
month = 0,
day = 0
):
self.year = year
# these three lines create the attributes of the new
Date object being created
self.month = month
self.day = day
However,
it sometimes useful for the __init__ function to do other things, and
it can do anything that any other function can do. For example,
we might want it to report what it is doing:
def __init__(self,
year = 0,
month = 0,
day = 0
):
self.year = year
self.month = month
self.day = day
print "Creating Date object with year
=",self.year,", month =",self.month,", day =",self.day
Here is another example of an __init__ that might be used for a Rectangle object:
class Rectangle(object):
def __init__(self, height = 0, width = 0):
self.height = height
self.width = width
self.area = height*width
Note
that this gives each Rectangle object an attribute that is not
supplied, but is calculated using the parameter values given when the
Rectangle instance is created.
box_1 = Rectangle(7,6)
creates a Rectangle object with three attributes: height, width, and area.
Object Instance Methods
We
can give our new objects any number of operations that they can carry
out on themselves. The Python file Book.py contains several examples of
things a Book object can do (adding a borrower, printing its borrowers,
etc.). Note that each instance method has self
as its first parameter, and we don't have to provide anything as an
argument to match that parameter. This is just the way Python
does it - when you are writing instance methods, remember to put self as the first parameter, and then ignore it. Note also that we have to put self.
in front of every attribute. This actually makes sense because in
many applications objects are allowed to modify the attributes of other
objects - so each attribute needs a prefix to specify exactly which
object it belongs to.
Class Attributes
Sometimes
it is useful to store information about an entire class of objects, as
opposed to about specific instances. We can do this using class attributes.
A class attribute looks like a variable initialization in the
class definition (usually at the top of it). For example, in our
Book class (see the accompanying Python file) we might want to keep
track of how many Book objects have been created. We can do this
with a class attribute called num_books (or any other name we like, such as counter or size_of_library or whatever). Then when we can add a line to __init__ so that every time we create a Book object, the num_books class attribute gets updated.
In the accompanying Python file Book.py, you will see two class attributes. The __init__ function updates both of them each time a Book object is created:
from Date import *
class Book(object):
# num_books and list_of_books are class attributes.
num_books = 0
list_of_books = []
def __init__(self,
title = "",
author = "",
date = Date(),
language = "",
value = 0.0,
borrowers = []
):
self.title = title
self.author = author
self.date = date
self.language = language
self.value = value
self.borrowers = borrowers
Book.num_books += 1
Book.list_of_books.append(self)
As well as class attributes, we can define class methods.
These allow us to work with class attributes without having to
refer to specific objects within the class. For example, in the
accompanying Python file you will find
@classmethod
def how_many(Book):
print "There are",Book.num_books,"books in the library"
@classmethod
def print_all_titles(Book):
for b in Book.list_of_books:
b.print_title()
These
are very simple examples - a class method can include any operation you
want. Note that the class attributes are prefixed with the class
name, (e.g. Book.num_books)
As an exercise, think of a type
of object of which you can think of several instances (phones, family
members, shoes, board games) and create a class definition for that
type of object. Write one or two instance methods and class
methods to become familiar with these concepts. If you can't
think of anything, try the old stand-by: create a class definition for
CISC_121_Student. But really, wouldn't Dr_Who_Episode be more
interesting?