6
Sep 12

Intro: Object Oriented Programming in python

This is a quick introduction to OOP and inheritance in python. A class is a container of attributes (can think of as variables) and methods (functions). Classes allow us to define a container that can consists of data and functions. An object can then be created that we can use which contains the data and has the functionality of those methods. An object is an instance of the class. In our example we have to classes.

Employee is the basic class which holds certain attributes (information) about the specific employee and the methods allow us to do things to that data.

Supervisor is the unique class which is a type of employee so it should have the same functionality. This functionality is "inherited" from the employee class so we don't have to rewrite it all. The only code we have to write for the supervisor class is the unique features that employee is lacking. The code for these two classes is below:


# Basic Object Oriented Programming


# Main Employee class
class Employee(object):

    def __init__(self, name, wage_rate, age):
        self.name = name
        self.wage_rate = wage_rate
        self.age = age
        self.vacation = 15
        self.sick_days = 20
        
    
    def use_sick_days(self, days_used):
        self.sick_days = self.sick_days - days_used
        
    def use_vacation(self, days_used):
        self.vacation = self.vacation - days_used
        
    def birthday(self):
        self.age += 1
        
    def get_age(self):
        return self.age
    
    def get_vacation(self):
        return self.vacation
    
    def get_sick_days(self):
        return self.sick_days
    
    

# This is a specific type of employee.  The
# supervisor inherits properties of the employee
# class, but also has additional functionality
class Supervisor(Employee):
    
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.wage_rate = 35
        self.vacation = 30
        self.sick_days = 30
        self.bonus_value = 0
        
    def bonus(self, bonus):
        self.bonus_value += bonus
        
    def get_bonus(self):
        return self.bonus_value

The first thing to do when developing a class is to type class 'class_name'(object): which tells python you are creating a class named 'class_name' and it ends with colons just like our logical statements. The object is a syntactical requirement if you are not inheriting from a class. If you would like your class to inherit functionality from another class then put the class name in (). Now that we have started our Employee class we need to define its attributes or internal variables. The variables we want to define upon the creation of the Employee object are put into the constructor.

The constructor is the __init__ function. This executes upon creating an object from Employee (which we will get to next). We want our object initialized with certain data inside so we set things such as: name, age, wage rate etc... Notice here that you can also pass in information to the constructor upon creating the object. This allows you to configure parts of your object upon creation. The self parameter ('self' in self.age) is required because it allows python to know that the variable belongs to a certain object or instance of the class. This will make more sense in a minute. The idea here is that you always pass it in because you can create multiple objects (instances) of the same class. If you have two, how is python going to know who's variables belong to who? To solve this problem self is always passed in by the appropriate object.

Under the Init function we have more definitions. These are the methods (functions) which manipulate information. The return statement at the end denotes that they are value returning functions. This means when they are done executing their instructions they return a value. This is just like an 'int' function in C. They are defined just like normal python functions allowing you to pass data to them if you want to. The constructor (__init__) is a function as well, just a special type. This covers the syntax of classes. The only other thing that might throw someone off is the '+='. This is a shorthand way of writing, for example, self.bonus =self.bonus + bonus.

Now lets create the objects and use them.



# create an object from employee
Timmy = Employee('Timmy', '15.00', '26')
print('Timmy')
# check out some attributes of object 'Timmy' using methods
print(Timmy.get_age())
print(Timmy.get_vacation())
print(Timmy.get_sick_days())
print('---------------------')


The first line of code creates and object. The object Timmy (which you can think of as a variable that holds both data and functionality) now has all of the associated functionality of the class employee. This means Timmy has an age, wage rate, sick time, vacation time. We can also give him a birthday which increments his age as well ass remove sick time and vacation. The syntax for creating object Timmy looks like a function call. This is where our constructor comes into play. The parameters passed into employee (Timmy, 15.00, 26) are really passed into the constructor and set just like you would set or process variables in a function. The self in the class associates the string 'Timmy', floating point number 15.00 and integer 26 with the instance Timmy. This means we can create another object called Tom with different parameters. The second object Tom would retain its own parameters and they would not get mixed up with Timmy's.

To access variables an methods in python objects we use dot notation. The print statement prints out whatever is inside the parentheses to the console (to screen). This gives us a way to see what our attributes hold and what our methods return. Since get age, get vacation and get sick days are value returning, we can stick them directly into the print function. When they finish executing code they will return a value. If get_age() finishes and returns 12, this would look like print(12). Lets run this and see what it returns in the console.

Timmy
26
15
20
---------------------

So, Timmy.get_age() returns a 26. Therefore our print statement is print(26) which prints 26 to the console. The dashes ( -------------- ) are just a separator so that you can run all of the code in OOP1.py and see it broken up. Next, we will run the same code, but add some formatting so when running this code it is easier to distinguish what is what. The way we do this is by adding the str() function and concatenating it with a text description. The string function takes whatever value is in parentheses and turns it into a string. The print function can print anything to screen but, they have to be of the same type. Concatenation is simply adding two things together linearly. This is easy to see with an example.

# add some formatting
print('Timmy')
print(str(Timmy.get_age()) + '  <- Age')
print(str(Timmy.get_vacation()) + '  <- Vacation Time')
print(str(Timmy.get_sick_days()) + '  <- Sick Days')
print('---------------------')

So what we've done is put our value returning method into the string function. This means that the method will return a number and then that number will get changed into a string. This is necessary because we want to put a little arrow with a description on the same line as Timmy's age variable. Since we put ' <- Age' (which is a string of text) we have to convert his age from an int to a string. The + sign here denotes concatenation which basically 'welds' the two together. It takes what is to the right of and attaches it to the right. Our result now looks like this:

# add some formatting
Timmy
26  <- Age
15  <- Vacation Time
20  <- Sick Days
---------------------

Now, lets create another class, and see how one class inherits the functionality of another. Our new class will be a supervisor so it needs to have the functionality of an employee with some additional modifications.

# create supervisor now
Robbie = Supervisor('Robbie', '32')

# check out some attributes of object 'Robbie' using methods
print('Robbie')
print(str(Robbie.get_age()) + '  <-- Age')
print(str(Robbie.get_sick_days()) + '  <-- Sick Days')
print(str(Robbie.get_vacation()) + '  <-- Vacation')
print(str(Robbie.get_bonus()) + ' <-- Bonus')

The first line creates an object, Robbie, of type supervisor. The code is pretty much the same so lets check out the result.

Robbie
32  <-- Age
30  <-- Sick Days
30  <-- Vacation
0 <-- Bonus

Since we have a different constructor, our attributes for this class are set to different values. Notice that we have the same functionality of employee and we have some custom methods. One is the bonus method. So far we have only been reading what has been set by the constructor. Lets changes some attributes.

# now lets use methods to make some modifications to our employee object
Timmy.use_sick_days(2)
Timmy.use_vacation(5)

print('Timmy')
print(str(Timmy.get_sick_days())+'  <-- Sick Days')
print(str(Timmy.get_vacation())+'  <-- Vacation days left')

And the result is:

Timmy
18  <-- Sick Days
10  <-- Vacation days left

In this example we have passed in values 2 and 5 which use methods in employee that decrement our sick days and vacation days by 2 and 5. The results show this was sucessful. Now, lets check out our inherited functionality.

# Now lets modify our supervisor object which will use some
# of the methods inherited from our employee class
print('Robbie - Original Sick days and vacation')
print(str(Robbie.get_sick_days()))
print(str(Robbie.get_vacation()))

# now modify
Robbie.use_sick_days(10)
Robbie.use_vacation(10)


print('Robbie - Modified Sick days and vacation')
print(str(Robbie.get_sick_days()))
print(str(Robbie.get_vacation()))

This example shows the values of sick days and vacation before we manipulate them. Here we are changing the attributes for Robbie by using the inherited methods from our Employee class. Lets see if this works.

Robbie - Original Sick days and vacation
30
30
Robbie - Modified Sick days and vacation
20
20

Hope this helps!

The .py file should be uploaded soon!