Programming Languages, Python

A Lesson about History, Objects, Classes, Time and Python

December 3, 2014

Object Oriented Programming (OOP) became very popular in the last couple of decades. I do find that a lot of people can tell me what an Object is, but few know what is the difference between a class and Object. In fact, many use them interchangeably. So let us clear the air a bit. Here is a short nice story about the evolution of programming. Sort of.

In the dawn of programming we had variables. For a time it was good. Char, Int, Sting, Float all run along nicely. For us programmers that was not enough. We like to make life more complex than that. So we start writing code. A lot of code. Code that uses a lot of variables. As programmers, we love looking for patterns. Slowly we found one. We are writing the same code, over and over. Now, we the coders are a lazy bunch. We like to be challenged, not to write the same lines of code again and agin. So, we came up with the notion of functions. Function are in fact awesome!. for a long time, one could do anything with a few variables and functions. Not to long after, we found ourself copying entire library of functions and files were getting really big. then we came up with the idea of modules, or libraries if you will. How awesome is it to import a whole battery of functions at your finger tips? Most programmers thought this was the best thing since slice bread. Not the we were around back then. After a while, we thought, you know what, how about we put the data (variables) and the methods (functions) together (encapsulation) and use it as one thing, lets call it an object. Yay! Objects.

This of course is a very short description of what actually happy. Hopefully you go the point. So what are objects? They are instantiation (from the word instants) of Classes with particular attributes and behaviors. Attributes refer to the object variables, behaviors to it’s functions. In most cases, but not all, the behaviors involve the attributes. Classes are the code, the recipe for an Object. 1 Class can produces as many Objects as you computer memory can hold. Having the attributes and behaviors together gives a sense of encapsulation. In OOP, the Object attributes are accessed using getters and setters (Access Modifiers). Getters retrieve a copy of the attribute. Setter overwrite the attributes. Setters and Getters are behaviors that help keep the information help by the Object correct. That means that if there is and attribute of a class that has to be a number between 0 and 10. The setter will not allow any other value to be stored. OOP gives us a sense of abstraction since we normally can’t see the code, but we don’t need to. There are a couple of more terms you should hear for now, inheritance and polymorphism. Inheritance means a class can be extended by another class to enhance functionality. Polymorphism means “of many forms”. This applies to OOP since we can have man ors of a single class.

Wow that was a lot to take in all at once. It is time for an example. What better language to use then our favorite, Python. Yay.

We are going to work on a time module that could be helpful for future programs. we are going to start from our basic class, an instant. For our purposes, an instant of time is date and time up to minute accuracy. That means that we are going to write a class, in Python, for an instant. We will have a date (year, month, day) and hour (hour, minute) as our class attributes. To set this up will have to use some special syntax. It will look like this:


class Instant:

	def __init__(self,year,month,day,hour,minute):
		self.year = year
		self.month = month
		self.day = day
		self.hour = hour
		self.minute = minute

Ok. We start with the keyword class, followed by the class name. then we define a function named __init__. This is a special function called a constructor. This function has to be in every class in order to create an object. It is only called once to set the Object up. As the function arguments we pass in self and the reminder of the variables we want to pass in to set the Object up. Some leagues allow multiple constructors. Python does not. We will pass self from this point to every function in the class, so that they can have access to the Objects attributes. Note that self.year is not the same as year. Self.year is the class variable, while year is a function variable.

To use this class, or to get an object, we can use the following code:


def main():

	i = Instant(2014,12,3,2,11)
	print i

if __name__== "__main__":
	main()

If you run it, you will get something that looks like this:

wpid-instantclasspython-2014-12-3-01-39.png

That number is a memory location where our object is stored. If we crated more Object they all will have different hex memory addresses. This is useful to know but not ver particle. If we want to debug or do anything we will need to print out the individual attributes within the class. Thankfully, there is a special function we can write called a to-string. It is noted in Python __str__ and will be called when asked to print the object. For our example the code will look like this:


def __str__(self):
	return  "Year: " + str(self.year) + " " + \
	   	   "Month: " + str(self.month) + " " + \
		   "Day: " + str(self.day) + " " + \
		   "Hour: " + str(self.hour) + " " + \
		   "Minute: " + str(self.minute)

And the output (for the same main() function from before):

wpid-instantstrpython-2014-12-3-01-39.png

You could be fancy and change the function to return something else like:

wpid-instantstrpython2-2014-12-3-01-39.png

if you really want you could play around with colors and strings in Python all that you want, but that is not the point. Now we are going to add some getters and setters. Getters are easy, the just retrieve information, so a getter for year looks like this:


def getYear(self):
	return self.year

We define getters to avoid direct access to class attributes. However, if we go back to out main we can issue a command ‘print i.year’ without an error. In order to avoid that we will add 2 underscores to the attribute name in the constructor. That will make the attribute private so only within the class using self.year we can access thee variable. So our new constructor will look like this:


def __init__(self,year,month,day,hour,minute):
	self.__year = year
	self.__month = month
	self.__day = day
	self.__hour = hour
	self.__minute = minute

And our getter will look like this:


def getYear(self):
	return self.__year

And if we wanted to print just the year, we would use it like this:


i.getYear()

Ideally, we would have a getter for every attribute in the class. That is not a must, just a friendly suggestion. Now we can move to the setters. In a setter, we will put a new value in the Object attribute. We could start with a simple method like this:


def setYear(self,year):
	self.__year = year 

This would work. However, normally it is a good idea to check what the user is putting as a year. In Python, variables do not have a declared type. That means that a user can end up passing in something like a String, Boolean or another Object for all we now. In addition, even if the user entered a number, what if it is a negative number? for our purposes, we are going to say that a year must be between 1900 and 2100. So our new setter will look like this:


def setYear(self,year):
	if not ((type(year) != type(2000)) or (year < 1900) or (year > 2100)):
		self.__year = year 

If you were following along you would notice a problem. When we first set self.year we never checked that the value of year upholds the setter standards. In order to correct this we would need to modify our constructor to do the same check. This does get tricky, but it is necessary to maintain the integrity f the Object data. We will modify our constructor set year line to look now like this:


if not ((type(year) != type(2000)) or (year < 1900) or (year > 2100)): self.__year = year
else: raise Exception('Year is not in correct format or out of range')

This means that for each variable we will need to similar work an add a getter and setter. Assuming we got all this done we could move forward. There are 3 more function we will want to added to our instant class:

  1. beforeMe
  2. afterMe
  3. addToMe

The first 2 functions are booleans that take another instant and compare the 2 to see if the other instant is before the current one. Similar idea with afterMe. The method add to me, will take a quantity and add it to instant. Lets take a look at the functions beforeMe and afterMe:

def beforeMe(self,other):
	if self.__year > other.getYear():
		return False
	elif self.__year == other.getYear():
		if self.__month > other.getMonth():
			return False
		elif self.__month == other.getMonth():
			if self.__day > other.getDay():
				return False
			elif self.__day == other.getDay():
				if self.__hour > other.getHour():
					return False
				elif self.__hour == other.getHour():
					if self.__minute > other.getMinute():
						return False
	return True

def afterMe(self,other):
	return not self.beforeMe(other)

I did get a little laze. I could have re-wrttien afterMe as a reverse to beforeMe, this seemed smoother to me. This function really should be straight forward. Lets move on to the next one. In the next one, we can add X minutes to an instant. That is cool and useful because it does require a little math. Let us first take a look at how this is done:


def add(self,min):
	if type(min) != type(1): raise Exception("Invalid minutes to add")
		self.__minute += min
		if self.__minute > 60:
			self.__hour += self.__minute / 60
			self.__minute = self.__minute % 60
			if self.__hour > 24:
				self.__day += self.__hour / 24
				self.__hour = self.__hour % 24
				if self.__day > 30:
					self.__month += self.__day / 30
					self.__day = self.__day % 30
					if self.__month > 12:
						self.__year += self.__month / 12
						self.__month = self.__month % 12

Do note that at this point I am making a lot of assumptions. I did not account for leap years and odd months. This function should be re-wrriten better, but for our sake right now it serves it’s purpose. So after all this is said and done, we should end up with a very interesting class that represents and instant, or a moment if you will in time. That class could be used to create many Objects. Even objects that interact with each other since we can compare 2 instants using the beofreMe and afterMe functions. Maybe next time we can extend this class to be used for a TimePeriod and maybe even a meeting in a schedule book.

Here is a link to the complete instant class in Python in case you want to play around with it.

If you enjoyed this post, please consider leaving a comment or subscribing to the RSS feed to have future articles delivered to your feed reader.

You Might Also Like

  • Paul

    Captain. I thought you might be interested in how your examples might be made
    more Pythonic.

    In Python, explicit getters and setters are rarely used. Properties
    are generally considered more Pythonic and elegant. Your example code could be
    reworked to look something like this.

    def __init__(self,year,month,day,hour,minute):
    self.year = year
    # and so on

    @property
    def year(self):
    return self._year

    @year.setter
    def year(self, year):
    if not ((type(year) != type(2000)) or (year 2100)):
    self._year = year

    Notice that this uses the more common single underscore to denote 'private'
    variables.

    The login in the setter property can also be made more pythonic as follows:

    @year.setter
    def year(self, year):
    if not isinstance(year, int):
    raise TypeError("Year must be an integer")
    if 1900 <= year <= 2100:
    self._year = year
    else:
    raise ValueError("Year must be in the range 1900 to 2100")

    With this change, the code will also catch invalid values passed to the
    __init__ method.