Non-Programmer's Tutorial for Python 3/Intro to Object Oriented Programming in Python 3< Non-Programmer's Tutorial for Python 3
Object Oriented ProgrammingEdit
Up until now, the programming you have been doing has been procedural. However, a lot of programs today are Object Oriented. Knowing both types, and knowing the difference, is very important. Many important languages in computer science such as C++ and Java, often use OOP methods.
Beginners, and non-programmers often find the concept of OOP confusing, and complicated. This is normal. Don't be put off if you struggle or do not understand. There are plenty of other resources you can use to help overcome any issues you may have, if this chapter does not help you.
This chapter will be broken up into different lessons. Each lesson will explain OOP in a different way, just to make sure OOP is covered as thoroughly as possible, because IT IS VERY IMPORTANT. Before the lessons, there is an introduction which explains key concepts, terms, and other important areas of OOP, required to understand each lesson.
Think of a procedure as a function. A function has a specific purpose. That purpose may be gathering input, performing mathematical calculations, displaying data, or manipulating data to, from, or in, a file. Typically, procedures use data which is separate from code for manipulation. This data is often passed between procedures. When a program becomes much larger and complex, this can cause problems. For example, you have designed a program which stores information about a product in variables. When a customer requests information on a product, these variables are passed to different functions for different purposes. Later on, as more data is stored on these products, you decide to store the information in a list or dictionary. In order for your program to function, you must now edit each function that accepted variables, to now accept and manipulate a list or dictionary. Imagine the time that would take for a program that was hundreds of megabytes, and hundreds of files in size! It would drive you insane! not to mention, errors in your code, are almost guaranteed, just because of the large volume of work and possibilities to make a typo or other error. This is less than optimal. Procedural programming is centered on procedures or functions. But, OOP is centered on creating Objects. Remember how a procedural program has separated data and code? Remember how that huge program was hundreds of files and would take FOREVER to edit? Well, think of an object as a sort of "combination" of those files and data into one "being". In a technical sense, an Object is an entity which contains data, AND procedures (code, functions, etc.).
Data inside an object is called a data attribute.
Functions, or procedures inside the object are called methods.
Think of data attributes as variables.
Think of methods as functions or procedures.
Let's look at a simple, everyday example. The light and light switch in your bedroom. The data attributes would be as follows.
- light_on (True or False)
- switch_position (Up or Down)
- electricity_flow (True or False)
The methods would be as follows.
The data attributes may or may not be visible. For example, you cannot directly see the electricity flowing to the light. You only know there is electricity, because the light is on. However, you can see the position of the switch (switch_position), and you can see if the light is on or off (light_on). Some methods are private. This means that you cannot directly change them. For example, unless you cut the wires in your light fixture (please don't do that, and for the sake of this example, assume that you don't know the wires exist), you cannot change the flow of electricity directly. You also cannot directly change if the light is on or off (and no, you can't unscrew the bulb! work with me here!). However, you can indirectly change these attributes by using the methods in the object. If you don't pay your bill, the
change_electricity_flow method will change the value of the
electricity_flow attribute to FALSE. If you flip the switch, the
move_switch method changes the value of the
By now you're probably thinking, "What does this have to do with Python?" or, "I understand, but how do I code an Object?" Well, we are almost to that point! One more concept must be explained before we can dive into code.
In Python, an object's data attributes and methods are specified by a class. Think of a class as a blueprint to an object. For example, your home - the object that you live in - you can also call it your pad, bungalow, crib, or whatever, was built based on a set of blueprints; these blueprints would be considered the class used to design your home, pad, crib, ahem, you get the idea.
Again, a class tells us how to make an object. In technical terms, and this is important here, a class defines the data attributes and methods inside an object.
To create a class, we code a class definition. A class definition is a group of statements which define an object's data attributes and methods.
Below is a Procedural program that performs simple math on a single number, entered by a user.
# Program by Mitchell Aikens # No Copyright # 2012 # Procedure 1 def main(): try: # Get a number to maniuplate num = float(input("Please enter a number to manipulate.\n")) # Store the result of the value, after it has been manipulated # by Procedure 2 addednum = addfive(num) # Store the result of the value, after it has been manipulated # by Procedure 3 multipliednum = multiply(addednum) # Send the value to Procedure 4 display(multipliednum) # Deal with exceptions from non-numeric user entry except ValueError: print("You must enter a valid number.\n") # Reset the value of num, to clear non-numeric data. num = 0 # Call main, again. main() # Procedure 2 def addfive(num): return num + 5 # Procedure 3 def multiply(addednum): return addednum * 2.452 # Procedure 4 def display(multi): # Display the final value print("The final value is ",multi) # Call Procedure 1 main()
If we were to enter a value of "5", the output would be as shown below.
Please enter a number to manipulate. 5 The final value is 24.52
If we were to enter a value of "g", and then correct the input and enter a value of "8", the output would be as shown below.
Please enter a number to manipulate. g You must enter a valid number. Please enter a number to manipulate. 8 The final value is 31.875999999999998
Below, is a Class, and a program which uses that class. This Object Oriented Program does the same thing as the procedural program above. Let's cover some important OOP coding concepts before we dive into the Class and program. To create a class, we use the
class keyword. After the keyword, you type the name you want to name your class. It is common practice that the name of your class uses CapWords convention. If I wanted to create a class named dirtysocks, the code would be:
The Class is shown first. The program which uses the class is second.
# Filename: oopexample.py # Mitchell Aikens # No Copyright # 2012 # OOP Demonstration - Class class NumChange: def __init__(self): self.__number = 0 def addfive(self,num): self.__number = num return self.__number + 5 def multiply(self,added): self.__added = added return self.__added * 2.452
The program which uses the class above, is below.
# Filename: oopexampleprog.py # Mitchell Aikens # No Copyright # 2012 # OOP Demonstration - Program import oopexample maths = oopexample.NumChange() def main(): num = float(input("Please enter a number.\n")) added = maths.addfive(num) multip = maths.multiply(added) print("The manipulated value is ",multip) main()
After looking at that program, you are probably a bit lost. That's OK. Let's start off by dissecting the class. The class is named "NumChange" There are three methods to this class:
These three methods each have a similar code.
def __init__(self): def addfive(self,num): def multiply(self,added):
Notice how each method has a parameter named "self". This parameter must be present in each method of the class. This parameter doesn't HAVE TO be called "self", but it is standard practice, which means you should probably stick with it. This parameter is required in each method because when a method executes, it has to know which object's attributes to operate on. Even though there is only one Object, we still need to make sure the interpreter knows that we want to use the data attributes in that class. So we play it safe...and use the "self" parameter.
Let's look at the first method.
Most Classes in Python have an
__init__ which executes automatically when an instance of a class is created in memory. (When we reference a class, an instance [or object] of that class is created.) This method is commonly referred to as the initializer method. When the method executes, the "self" parameter is automatically assigned to the object. This method is called the initializer method because is "initializes" the data attributes. ↵Under the __init__ method, we set the value of the
number attribute to 0 initially. We reference the object attribute using dot notation.
def __init__(self): self.__number = 0
self.__number = 0 line simply means ""the value of the attribute "number", in the object, is 0"".
Let's look at the next method.
def addfive(self,num): self.__number = num return self.__number + 5
This method is named "addfive". It accepts a parameter called "num", from the program using the class. The method then assigns the value of that parameter to the "number" attribute inside the object. The method then returns the value of "number", with 5 added to it, to the statement which called the method.
Let's look at the third method.
def multiply(self,added): self.__added = added return self.__added * 2.453
This method is named "multiply". It accepts a parameter named "added". It assigns the value of the parameter to the "added" attribute, and returns the value of the "added" attribute multiplied by 2.452, to the statement which called the method.
Notice how the name of each method begins with two underscores? Let's explain that. Earlier we mentioned that an object operates on data attributes inside itself using methods. Ideally, these data attributes should be able to be manipulated ONLY BY METHODS IN THE OBJECT. It is possible to have outside code manipulate data attributes. To "hide" attributes, so only methods in the object can manipulate them, you use two underscores before the object name, as we have been demonstrating. Omitting those two underscores in the attribute name, allows for the possibility of manipulation from code outside the object.
Let's look at the program which uses the class we just dissected.
Notice the first line of non comment code.
This line of code imports the class, which we have saved in a separate file (module). Classes do not have to be in a separate file, but it is almost always the case, and thus is good practice to get used to importing the module now.
The next line:
maths = oopexample.NumChange()
This line creates an instance of the NumChange class, stored in the module named "oopexample", and stores the instance in the variable named "maths". The syntax is:
modulename.Classname() Next we define the main function. Then, we get a number from the user.
The next line
added = maths.addfive(num) sends the value of the "num" variable to the method named "addfive", which is part of the class we stored an instance of in the variable named "maths", and stores the returned value in the variable named "added".
The next line
multip = maths.multiply(added) sends the value of the variable "added", to the method named "multiply", which is part of the class we stored an instance of in the variable named "maths", and stores the returned value in the variable named "multip".
The next line prints "The manipulated value is <value of multip>". The last line calls the main function which executes the steps outlined above.