OOP » Defining Classes »

 

Defining Classes

Text Files Table Of Contents Operator Overloading


Since Python is an object-oriented scripting language it must provide a means for you to define your own classes. Defining and using classes is much easier in Python than other languages such as C++ and Java. In addition to standard object-oriented concepts, Python also allows for multiple inheritance and operator overloading.

In object-oriented languages, an object is an entity corresponding to an underlying objective. The object stores data for the given entity. A class represents a collection of related objects and is the blueprint which defines the construction of an object. Objects are instantiated or created from classes.

The Class

A class is the blueprint which defines the construction of an object. A class definition contains

  • data fields — (or attributes)variable declarations for the data stored in each instantiated object.
  • methods — (or services)the operations that can be performed on an object to manipulate its data. Methods contain statements that are executed when the method is invoked or executed (method call).

Objects are instantiated or created from classes. A class of objects is the collection of objects created from the same class (i.e. a collection of float objects.).

Sample Class

Consider a class for defining and representing two-dimensional discreet points. First, the Java implementation

Program: Point.java
// Point.java
// Defines a class to represent two-dimensional discrete points.

public class Point {
  private int xCoord;
  private int yCoord;

  public Point() {
    xCoord = yCoord = 0;
  }

  public Point( int x, int y ) {
    xCoord = x;
    yCoord = y;
  }

  public String toString() {
     return "(" + xCoord + ", " + yCoord + ")";
  }

  public int getX() { return xCoord; }

  public int getY() { return yCoord; }

  public void shift( int xInc, int yInc ) {
    xCoord = xCoord + xInc;
    yCoord = yCoord + yInc;
  }
}
 

and now the corresponding Python implementation

Program: point.py
# point.py
# Defines a class to represent two-dimensional discrete points.

class Point :
   def __init__( self, x = 0, y = 0 ) :
      self.xCoord = x
      self.yCoord = y
     
   def __str__( self ) :
      return "(" + str( self.yCoord ) + ", " +
                   str( self.yCoord ) + ")"
     
   def getX( self ) :
      return self.XCoord
     
   def getY( self ) :
      return self.yCoord
     
   def shift( self, xInc, yInc ) :
      self.xCoord += xInc
      self.yCoord += yInc
 

The Python class definition is a compound statement which requires all member defintions to be indented to the same level from that of the class keyword.

NoteNote:

By default, all members or attributes of a Python class are public. Python provides a mechanism for defining private members, but we omit that discussion at this time and assume the user of a class will not directly modify a data field.

It has been mentioned several times that everything in Python is an object. We saw that not only are data types objects, but function definitions were also objects and function names are variables. The same is true for classes. A class definition creates an object with the various attributes (data fields and methods) and the class name is simply a variable referencing that object.

Object Instantiation

Objects are created for a user-defined class the same as for the built-in classes. The following example illustrates the use of the Python Point class

from point import *

pointA = Point( 5, 7 )
pointB = Point()
 

which results in two objects, each with its own instance variables

If the class is defined in a separate module as is done here, then we must import it before it can be used. In Java, each class had to be defined within its own file which was named the same as the class. This is not the case in Python. Multiple classes can be defined within a single module and the module name is independent of any definition it may contain.

Methods

Objects are manipulated using methods defined by the corresponding class. A method contains declarations and executable statements to manipulate the given object.

Method Definition

A method definition is similar in appearance to that of a function. There are two main differences, however. First, a method is defined as part of a class definition as indicated by its indentation in respect to the class header. Second, a class method must contain the self reference as its first argument.

The reserved word self within the method defintions is equivalent to this in Java. A major difference, however, is Python requires you to use the self reference while in Java it was hidden and only needed in special cases. Even though the self reference is the first argument of the method definition, it is not used directly when a method is called. Consider the following method call for the pointA object created above.

pointA.shift( 10, 15 )
 

From the definition of the adjust() method above, it appears that three actual arguments are required. But Python automatically passes the object reference to the method. A method invocation of the form

instance.method( args... )

is converted into a method call of the form

class.method( instance, args...)

Constructor

The constructor of a Python class is defined using the special name __init__. A class may only contain a single constructor. To provide multiple constructor options, you must use default values as was done in the Point class example or use inheritance to create a new derived class with a new constructor.

NoteNote:

While a class does not have to define a constructor, it is good practice to always provide one, especially if the class contains data fields.

Special String Method

In Java, a class could contain the toString() method which was used automatically when printing the value of an object or that object had to be converted to a string. Python defines the __str__() method for the exact same thing. In the following example,

print "pointA: ", pointA
print "pointB: ", pointB
 

the __str__() method is automatically called since we are trying to print the contents of the object. The same as would have been done in Java with the toString() method. In Java, you could use the toString() method directly

// Java method call
String myString = pointA.toString();
 

In Python, the __str__() method can not be directly invoked. Instead, it is treated as an operator and can be used indirectly via the str() constructor. In this example,

myString = str( pointA )
 

the __str__() method is called by the str() constructor to convert our point object to a string. If the __str__() method is not defined for a class, Python uses the default action of printing the object type and its reference address.

NoteNote:

Class methods of the form __xyz__() are actually operator definitions and can not be called directly. Instead, they are called automatically for the appropriate operator. In our example above, the __init__() method is automatically called when creating an object and the __str__() method is automatically called when converting the object to a string.

Data Fields

In Python, data fields like all other variables are not explicitly defined. Instead, any instance variable created within the constructor or a method becomes a data field.

Instance Variables

Instance variables are specified by preceding the name with the self reference. Even though a data field can be defined within any method, common practice dictates that data fields should be defined within the constructor. The Point class defines two data fields in the constructor, xCoord and yCoord,

def __init__( self, x = 0, y = 0 ) :
   self.xCoord = x
   self.yCoord = y
 

while the two arguments, x and y, are simply local variables that can be used within the constructor. Just as in Java, data fields can be used within any method. But you must remember to precede the data field name with the self reference.

Mutable Objects

Any object that stores data is said to have a state. The object’s state is the current set of values that it contains. Objects are divided into two distinct categories: mutable and immutable An immutable object is one in which the state cannot be changed once it is created. If the data fields of the obect can be changed after the object is created, the object is said to be mutable. In Python only the list, dictionary, and file primitive types are mutable.

Object Composition

Python objects are typically composed of other objects. In the class defined above, a Point object contains two numeric coordinate values. In object-oriented terminology, we call this a has-a relationship since a Point has numeric values. Consider the following class definition

Program: line.py
# line.py
#
import math

class Line :
   def __init__( self, fromPoint, toPoint ) :
      self.startPoint = fromPoint
      self.endPoint = toPoint

   def length( self ) :
      xDiff = self.startPoint.getX() - self.endPoint.getX()
      yDiff = self.startPoint.getY() - self.endPoint.getY()
      return math.sqrt( xDiff * xDiff + yDiff * yDiff )

   def slope( self ) :
      if isVertical() :
         return None
      else :
         run = self.startPoint.getX() - self.endPoint.getX()
         rise = self.startPoint.getY() - self.endPoint.getY()
         return rise / float( run )

   def isVertical( self ) :
      return self.startPoint.getX() == self.endPoint.getX()

   def isHorizontal( self ) :
      return self.startPoint.getY() == self.endPoint.getY()

   def shift( self, x, y ) :
      self.startPoint.shift( x, y )
      self.endPoint.shift( x, y )

   def getStartPoint( self ) :
      return self.startPoint
     
   def getEndPoint( self ) :
      return self.endPoint
 

which defines a geometric line in the two-dimensional Cartesian coordinate system; a Line line is composed of two Point objects.

Class Examples

The following examples further illustrate the use of classes in Python. The first example creates a class to represent a die that can be tossed using the random number generator.

from random import randint

class Die :
   def __init__( self, numFaces ) :
      if numFaces < 4 :
         self.numFaces = 4
      else :
         self.numFaces = numFaces
      self.faceValue = 1

   def roll( self ) :
      self.faceValue = randint( 1, self.numFaces )
      return self.faceValue

   def value( self ) :
      return self.faceValue

   def __str__( self ) :
      return "[%d ! %d]" % (self.faceValue, self.numFaces )

# The main routine.
die1 = Die()
die2 = Die( 12 )

print die1.roll()
print die2.roll()
 

In the next example, we define a class to represent a student record and provide serveral operations for obtaining information from that data.

# student.py
#
# Defines a class to represent information for an individual student.

def class Student :
   "Represents an individual student."
   def __init__( self, idNum = 0, classStanding = 0,
                 firstName = "", lastName = "",
                 gpa = 0.0 ) :
      self.idNum = idNum
      self.classStanding = classStanding
      self.firstName = firstName
      self.lastName = lastName
      self.gpa = gpa

   def getClass() :
        """Returns the string representation for the student's
           classification code."
""

      if self.classStanding == 0 :
         return "Freshman"
      elif self.classStanding == 1 :
         return "Sophomore"
      elif self.classStanding == 2 :
         return "Junior"
      else
         return "Senior"

   def getName( reversed ) :
        """Returns the student's name in one or two formats:
           'first last' if reversed is false or 'last first'
           if reversed is true."
""

      if reversed == False :
         return self.firstName + " " + self.lastName
      else :
         return self.lastName + " " + self.firstName

   def getId() :
      return self.idNum

   def getGPA() :
      return self.gpa
 

The getClass() method is a common implementation for the problem of selecting a descriptive name for a code representation. We could use a list and create a more compact form as shown below

def getClass( self ) :
   classList = [ "Freshman", "Sophomore",
                 "Junior", "Senior" ]
   return classList[ self.classStanding ]
 

We then use this class to create a second class to store a list of student objects. The Student List class is also defined within the student.py module.

def class StudentList :
   def __init__( self ) :
      self.theList = []

   def addStudent( self, student ) :
      self.theList.add( student )

   def deleteStudent( self, idNum ) :
      return None

   def findStudent( self, idNum ) :
      return None

   def findHighestGPA( self ) :
      return None

   def printReport( self ) :
      return None
 

Static Members



Text Files Table Of Contents Operator Overloading

© 2006 - 2008: Rance Necaise - Page last modified on September 30, 2006, at 07:03 PM