Class Inheritance and Composition
Creating new classes
through composition
Now we�ll
create a new class, UTM_Lineseg, which represents a straight line segment in 2D space
The segment
will be bounded by objects of the class UTM coordinates
Composition
means that some of our class member variables are objects of some other class
Note: if the �other class� is defined in
a separate module, you must import that module and refer to it as module_name.class_name (or use the shorthand name introduced
by the keyword �as�), e.g.
import UTM_Coord as uc
# UTM_Coord is module name, uc
is shorthand
class someClass:
def __init__(self):
#
Since UTM_Coord is defined in another module,
#
refer to it by its module name or shortcut name, as below
self.myCoord = uc.UTM_Coord(580000, 4720000, 18, �N�)
The code for creating SimpleUTM_Lineseg
is here (Save as SimpleClassByComp.py
in the same folder as UTM_Coord.py)
We build a UTM_Lineseg class through a very simple constructor that accepts 2 UTM_Coord objects
Although this
class is ok if the user works carefully, it can break easily if the user
supplies incorrect arguments
We should
check whether the user of the class has supplied the correct arguments
The code for safely building a class through composition
is here (save as UTM_Lineseg.py
in the same folder as UTM_Coord.py)
A safe class
fails �gracefully� (with error messages�not by crashing your program)
Our safer
class will look like this:
import math # this class is referred to in length()
class UTM_Lineseg:
� def __init__(self, p0, p1):
if not isinstance(p0, UTM_Coord):
# if p0 is not
���������������������������������
# a UTM_Coord object�
print "p0 is not a UTM_Coord
object" # stop doing stuff
self.p0 = None # create an empty object that can be tested for
self.p1 = None
return
if not isinstance(p1, UTM_Coord):
print "p1 is not a UTM_Coord
object"
self.p0 = None
self.p1 = None
return
# if we got here, p0 and p1 are OK
self.p0 = p0
self.p1 = p1
def length(self):
if self.p0 == None or self.p1 == None: # bad arguments
print "Invalid line segment--cannot compute
length"
return -1
if self.p0.zone != self.p1.zone or self.p0.hemisphere !=
self.p1.hemisphere:
print "cannot find length of line crossing UTM
zones or hemispheres"
return -1
������ # All is well. Calculate and return the
length
deltaE = self.p0.easting - self.p1.easting
deltaN = self.p0.northing - self.p1.northing
deltaE_squared = deltaE * deltaE
deltaN_squared = deltaN * deltaN
return math.sqrt(deltaE_squared + deltaN_squared)
Classes that are built by composition use objects of classes
just like other classes use built-in data types
Creating classes through inheritance
Inheritance lets you create a new class by extending, or inheriting
from, and existing class
The code for building a class through
inheritance is here (save as Road.py
in the same folder as your other class files)
Let�s extend the UTM_Lineseg class to make a Road class
For now, the Road class
will add just one more class member variable�a name for the road
Road
inherits from UTM_Lineseg, meaning that it has all the characteristics of the
inherited class (2 bounding UTM_Coord objects and a length()
method) plus it has a name
We can refer to Road
as a �child� class of UTM_Lineseg (the �parent� class):
import UTM_Lineseg as ul
class Road(ul.UTM_Lineseg): # Road inherits
from UTM_Lineseg
def __init__(self, n, p0, p1):
# add name as a Road class member variable and assign n
self.name = n
# init class
member variables of inherited class�������������
ul.UTM_Lineseg.__init__(self, p0, p1)
Most child classes will call the parent�s constructor:
ul.UTM_Lineseg.__init__(self, p0, p1)
We can now refer to the starting and ending nodes of a Road
object as p0 and p1, just as if they were defined explicitly in the Road class
The following code in the Road class does just that:
def report(self):
TAB = '\t'
TAB2 = TAB + TAB
nameField = 'name: ' + TAB + self.name
p0CoordField = TAB2 + 'p0: easting: ' + str(self.p0.easting) + ', northing: ' + str(self.p0.northing)
p0UTMField = TAB2 + 'p0: UTM zone: ' + str(self.p0.zone) + self.p0.hemisphere
p1CoordField = TAB2 + 'p1: easting: ' + str(self.p1.easting) + ', northing: ' + str(self.p1.northing)
p1UTMField = TAB2 + 'p1: UTM zone: ' + str(self.p1.zone) + self.p1.hemisphere
lengthField = TAB2 + 'length: ' + str(self.length()) + ' meters'
print nameField
print p0CoordField
print p0UTMField
print p1CoordField
print p1UTMField
print lengthField
Code for testing out the Road
class is here (save as BuildingRoads.py
with your other classes)
Try building a new class, Political_Border, that also inherits from UTM_Lineseg
Add some class member variables and methods that are useful
for dealing with borders
Here is a link to a set of
related geometric and topological classes to play with