Friday 4 April 2014

Classes, don't know why but here they are

I have been a coward for too long, so today I finally gave Python classes a bash. Well, I shall try to make this as brief as possible as it seems that one of the main problems with class tutorials is the long rambling on about the true nature of this and that. No philosophy here, lets just get some functional code down.
In this script we will define a type of thing, an “object” in parlance of who ever is that gets excited about these matters. This object is a pixel like thing, it has x,y and z coordinates and we could just call it a “point” but I’ve called it a pixel. When this pixel is passed another pixel by the script it calculates the distance between itself and the other Pixel. That’s pretty much it. Of course, there will be some other stuff in there just to illustrate the various bits and pieces that are “objects” and “classes” but I’ll try to make the annotations as helpful as possible.
Let us begin:
#! /usr/bin/python
import sys
import os
#
# Create our class.
class Pixel:
    # Set a counter for how many objects of this class we have created.
    pixelCount = 0
    # This is the initialisation bit. We pass the new object 3 values.
    # If we only pass 2 values the 3 is assigned a default value.
    def __init__(self, east,north,elev = 0):
        # Now we give the values passed to the initialing thingy to internal variables.
        self.easting = east
        self.northing = north
        self.elevation = elev
        # Then we increase the class counter by 1.
        Pixel.pixelCount += 1
Not too painful so far. Create the class, i.e. the template for the objects. It doesn’t do much but it does keep track of how many objects there are and each object can hold its own coordinates. The pixelCount is not needed but it may come in handy and here it serves to illustrate what can be done.
We can now continue to define functions for the class. Of course functions aren’t called “functions”, they are called “methods” because …
#! /usr/bin/python
import sys
import os
# Create our class.
class Pixel:
    # Set a counter for how many objects of this class we have created. This is shared by
    # all "Pixels"
    pixelCount = 0
    # This is the initialisation bit. We pass the new object 3 values.
    # If we only pass 2 values the 3 is assigned a default value.
    def __init__(self, east,north,elev = 0):
        # Now we give the values passed to the initialing thingy to internal variables.
        self.easting = east
        self.northing = north
        self.elevation = elev
        # Then we increase the class counter by 1.
        Pixel.pixelCount += 1
    #
    # This function doesn't do a great deal other than tell you how many pixels you have.
    def counter(self):
        print 'Total number of pixels: %s' % Pixel.pixelCount
    #
So the first new function (method) just prints the object count to the screen, that is, it tells you how many objects of the type “Pixel” have been created. It can do this because we set up a variable in that first bit of the class definition, before the __init__ bit, that is shared by all objects created from this class.
Now lets do something more adventurous. Lets calculate the 2D and 3D distances.
#! /usr/bin/python
import sys
import os
# Create our class.
class Pixel:
    # Set a counter for how many objects of this class we have created.
    pixelCount = 0
    # This is the initialisation bit. We pass the new object 3 values.
    # If we only pass 2 values the 3 is assigned a default value.
    def __init__(self, east,north,elev = 0):
        # Now we give the values passed to the initialing thingy to internal variables.
        self.easting = east
        self.northing = north
        self.elevation = elev
        # Then we increase the class counter by 1.
        Pixel.pixelCount += 1
    #
    # This function doesn't do a great deal other than tell you how many pixels you have.
    def counter(self):
        print 'Total number of pixels: %s' % Pixel.pixelCount
    #
    # This is a function (method if you want to get all technical) that uses the object's
    # own variables plus some other thing.
    def dist2d(self,other):
        # That other thing is another Pixel object, so check that that is what it is.
        if not isinstance(other, Pixel):
            sys.exit(1)
        # A little unnecessary this but lets just pass variable values on.
        e1, n1 = self.easting, self.northing
        e2, n2 = other.easting, other.northing
        # Some calculation (remember Pythagoras?)
        edif = e2 - e1
        ndif = n2 - n1
        dist2 = (edif**2 + ndif**2)**0.5
        # Talk to the user.
        print 'Eastings: %s - %s = %s' %(e2,e1,edif)
        print 'Northings: %s - %s = %s' %(n2,n1,ndif)
        print 'Distance in 2D: %s\n' %(dist2)
        # Return the calculated value to whatever called the function (method)
        return dist2
    #
    # As before but this time in glorious 3D.
    def dist3d(self,other):
        if not isinstance(other, Pixel):
            sys.exit(1)
        e1, n1, z1 = self.easting, self.northing, self.elevation
        e2, n2, z2 = other.easting, other.northing, other.elevation
        edif = e2 - e1
        ndif = n2 - n1
        # We don't really need to create too many new variables,
        # so lets just use what we have. Get the vertical distance directly from the
        # object's self storage.
        zdif = other.elevation - self.elevation
        dist3 = (edif**2 + ndif**2 + zdif**2)**0.5
        print 'Eastings: %s - %s = %s' %(e2,e1,edif)
        print 'Northings: %s - %s = %s' %(n2,n1,ndif)
        print 'Elevation: %s - %s = %s' %(other.elevation,self.elevation,zdif)
        print 'Distance in 3D: %s\n' %(dist3)
        return dist3
So both the new functions (methods) work in the same way. We give the function the thing called “self” i.e. the object owning the function (not the class but an object created following the template defined by the class). We also give it some other thing, which is another object also created from the Pixel class. It too contains the same functions (methods) but they aren’t used here, we only need the other object’s coordinates.
Now lets initiate some objects and play around a little.
##! /usr/bin/python
import sys
import os
# Create our class.
class Pixel:
    # Set a counter for how many objects of this class we have created.
    pixelCount = 0
    # This is the initialisation bit. We pass the new object 3 values.
    # If we only pass 2 values the 3 is assigned a default value.
    def __init__(self, east,north,elev = 0):
        # Now we give the values passed to the initialing thingy to internal variables.
        self.easting = east
        self.northing = north
        self.elevation = elev
        # Then we increase the class counter by 1.
        Pixel.pixelCount += 1
    #
    # This function doesn't do a great deal other than tell you how many pixels you have.
    def counter(self):
        print 'Total number of pixels: %s' % Pixel.pixelCount
    #
    # This is a function (method if you want to get all technical) that uses the object's
    # own variables plus some other thing.
    def dist2d(self,other):
        # That other thing is another Pixel object, so check that that is what it is.
        if not isinstance(other, Pixel):
            sys.exit(1)
        # A little unnecessary this but lets just pass variable values on.
        e1, n1 = self.easting, self.northing
        e2, n2 = other.easting, other.northing
        # Some calculation (remember Pythagoras?)
        edif = e2 - e1
        ndif = n2 - n1
        dist2 = (edif**2 + ndif**2)**0.5
        # Talk to the user.
        print 'Eastings: %s - %s = %s' %(e2,e1,edif)
        print 'Northings: %s - %s = %s' %(n2,n1,ndif)
        print 'Distance in 2D: %s\n' %(dist2)
        # Return the calculated value to whatever called the function (method)
        return dist2
    #
    # As before but this time in glorious 3D.
    def dist3d(self,other):
        if not isinstance(other, Pixel):
            sys.exit(1)
        e1, n1, z1 = self.easting, self.northing, self.elevation
        e2, n2, z2 = other.easting, other.northing, other.elevation
        edif = e2 - e1
        ndif = n2 - n1
        # We don't really need to create too many new variables,
        # so lets just use what we have. Get the vertical distance directly from the
        # object's self storage.
        zdif = other.elevation - self.elevation
        dist3 = (edif**2 + ndif**2 + zdif**2)**0.5
        print 'Eastings: %s - %s = %s' %(e2,e1,edif)
        print 'Northings: %s - %s = %s' %(n2,n1,ndif)
        print 'Elevation: %s - %s = %s' %(other.elevation,self.elevation,zdif)
        print 'Distance in 3D: %s\n' %(dist3)
        return dist3
#
# Time to create some objects.
# Create object "a" with Easting = 10, Northing = 10, Elevation = 10.
a = Pixel(10,10,10)
# Create object "b" etc.
b = Pixel(50,45,20)
# Now get to work by assign the variable "ans1" the value returned
# by sending Pixel object "b" to the dist2D function (method) of Pixel object "a"
ans1 = a.dist2d(b)
# Same again but in 3D
ans2 = a.dist3d(b)
print 'ans1 and ans2: %s %s\n' %(ans1,ans2)
print 'Call Pixel.pixelCount Number of pixels is %s' % Pixel.pixelCount
print 'Then call a.counter()'
a.counter()
print 'Then call b.counter()'
b.counter()
#
# What about only sending 2 coordinates?
c = Pixel(20,30)
ans3 = a.dist3d(c)
print '\nans3',ans3
print 'Call Pixel.pixelCount Number of pixels is %s' % Pixel.pixelCount
print 'Then call c.counter()'
c.counter()
#
# We can call an objects variables whenever.
print '\nEasting for a: ', a.easting
# We can even assign it some new ones
a.distTo_b = ans2
print 'Distance a to b: ', a.distTo_b
# It doesn't even have to make sense.
a.stupidName = 'Wibble'
print 'New attribute value: ', a.stupidName
Have fun.

No comments:

Post a Comment