Table of Contents |
Before we discuss object-oriented programming and classes, let’s review a few things that we have learned in this course up to this point.
In Units 1 and 2, we learned the four basic programming structures for writing code:
for
and while
loops to repeat a process or move through a data collection type.myVar = “Hello World”
. We have created many variables since then. We also explored various uses of data collection types like lists, sets, tuples, and dictionaries and the behaviors and properties of each.
We have seen and discussed some poorly written code and had hands-on experience with writing good code. And even then we took good code and optimized it. It took three iterations for the Tic-Tac-Toe game but in the end, it was a much better game and provided a much better player experience. Hopefully, at this point in the course, you are starting to see that there is a bit of art and aesthetic to writing code.
And finally, you have likely noticed that our programs are getting longer and longer as we continue to learn new functionality that exists within Python. So it makes sense that the more experienced we become, if the solutions dictate the need, the longer the programs will become.
Some programs can get to be millions of lines long! The average modern high-end car can contain up to 100 million lines of code. Here is a fun statistics site that references average lines of code per application: www.informationisbeautiful.net/visualizations/million-lines-of-code/
So, why this recap?
Well, a few things:
Why use OOP?
The structure and organization of the object-oriented programming model make code more reusable, more scalable, and more efficient. To do this, OOP structures programming into reusable pieces of code (classes) that we can create individual instances of objects from. The key to this challenge is to have a basic understanding of how objects are constructed and how they function, and most importantly, how we make use of the capabilities of objects that are provided to us by Python. This is an entry-level course in Python so we will touch on the basics of OOP, but know that there is much more capability to it.
Object-Oriented Programming
Object-oriented programming (or OOP for short) is a programming model that organizes the design of code by bundling objects.
What does a class look like? It has a class name, and typically contains attributes and methods.
What is a class?
A class is basically a piece of code where we can generate a unique object, much like a template. We can think of classes as a blueprint or a factory in which we can create individual objects using that template. In the example above, Dog
is a class; however, it doesn’t contain any actual data. Classes contain fields for attributes and methods. Our class only contains the attributes and methods (behaviors) that are common to all dogs. The Dog
class does specify that names, color, age, etc. are important to define a dog and that dogs should have behaviors like barking and fetching, but it does not have any specific data about any particular dog.
Don’t worry about the code yet, as we’ll get to this in upcoming lessons, but this is an example of a class.
EXAMPLE
class Dog:
def __init__(self,name,breed,age,color):
self.name = name
self.breed = breed
self.age = age
self.color = color
def bark(self):
print("Woof")
def fetch(self):
print(self.name," went to fetch.")
But how do we use this class?
In order to use a class, we need to create an instance of that class which is called an object. This process is called class instantiation. Therefore, objects are an instance of a class that has properties (attributes) and methods that are encapsulated or part of it. The object (instance) is uniquely created from the class and has data attributes that contain values that are unique to it. So, if we created an instance of the Dog
class, this instance (object) is no longer a blueprint. This instance now contains actual data like a dog's name (Fluffy, for example), who is brown, a beagle, and is 2 years old.
EXAMPLE
# an instance of theSnipping Dog class
my_dog = Dog("Fluffy","Beagle",2,"Brown")
print(my_dog.name)
print(my_dog.breed)
print(my_dog.age)
print(my_dog.color)
Here is that output screen.
Fluffy
Beagle
2
Brown
But haven’t we been using classes all along? Yes, we have!
Remember that we said that every item in Python is an object. This is true as every item will have methods that can be called from them, including strings or integers.
Think back to some of the objects we have used, like strings, and what methods we used on them. That was using classes. A lot of the functionality behind how the string methods are used is completely hidden away from you as the user of the class. We don’t have to worry about anything other than the method that we’re calling within the class, the parameters, and the return type. This allows us as the developers to just focus on the part of the problem that we have to solve and ignore all of the other parts of the program that are already implemented for us.
Let’s see how that works for a variable called 'my_string
using the methods .upper()
and .lower()
.
EXAMPLE
my_string = "Sophia"
print(my_string.upper())
print(my_string.lower())
Now for the output screen.
SOPHIA
sophia
Without us having to implement those methods to convert the string to lowercase and uppercase, we can simply make use of the existing methods that have been created for this purpose. In doing so, we convert the string all to uppercase characters and separately all to lowercase characters.
So, what is the purpose of a class?
Think of a class like a cookie-cutter and the objects created using the class are the cookies. You don’t put frosting on the cookie-cutter; you put frosting on the cookies, and you can put different frosting on each cookie. The frosting in this case represents the attributes or properties within the object. Each individual cookie with the frosting is considered as an object/instance of the class.
In our example, the Dog class (template for creating dogs) will not change but each instance we create from it can. So, we could create other instances like these:
EXAMPLE
my_dog1 = Dog("Fluffy","Beagle",2,"Brown")
my_dog2 = Dog("Mochi","Mutt",5,"White")
my_dog3 = Dog("Wolfie","Maltese",10,"Black")
In each one of these instances we do not have to redefine the attributes and methods since they were originally defined in the Dog class.
Class Instantiation
The process of creating an instance of a class which is called an object.
Before we discuss the attributes and methods of a class, it is important to bring up the term encapsulation again. We first coined this term in Unit 2 when we were discussing nested functions and a way to bundle functionality into a single unit. Now that we are discussing bundling objects as part of the OOP model, encapsulation is very important to classes as well.
In object-oriented programming, encapsulation is an important concept. Encapsulation helps describe the concept that we can wrap attributes and methods that work on data in a single class. This allows us to add some restrictions to the direct access of attribute variables and methods. To prevent attributes from being directly changed, a class’s attributes can be set to only be changed by its own class's method(s). For example, if we had a numeric grade attribute in a grade book object, we may want to force it to only be set between the numbers 0 and 100. A user should not be able to make a change to allow a negative number or have bonus points as part of the rules of encapsulation.
Back to our class example.
So, we know that a class is a blueprint or template from which objects or instances are created, but we also mentioned that a class contains fields for attributes and methods. Let's dive into those.
Attributes
Attributes can also be known as properties of an object. Attributes are variables that are defined in a class template and are the characteristics or properties of an object. In our example, color, breed, and age will be properties of the class Dog.
Methods
We have used methods previously. Methods are a specialized type of procedure that’s directly associated with an object and called to perform a specific task by using the object name, a period, and then the method name. When individual objects are created from the class, these objects can call a method that was defined in the class. Since methods perform actions, a method might change or update an object’s data (attribute) or possibly return some information. In our example, some behaviors or actions of the Dog
class are functions, including barking and/or fetching.
You will get a better understanding of each of the items of a class as we move through this challenge. Understanding the basics of a class is key to utilizing the OOP model.
An Example Class
Next, let’s see a class and get to know some of the syntax aspects of it. Here is an example that we will break down.
EXAMPLE
class PeopleCounter:
x = 0
def anotherOne(self) :
self.x = self.x + 1
print("So far",self.x)
In the first line of code, we use the class
keyword.
class PeopleCounter:
The class keyword defines the data and code that will make up each of the objects. When defining a class, it starts with the class
keyword and is then followed by the name of the class and a colon. In our example above, we are defining a class called PeopleCounter
.
But that is just the start of declaring a class; we can't just have that line alone. We need to include something about this new class. Notice that after the first line, the rest of the lines are indented. This means they are included in the class. It consists of attributes and methods of that class.
Do you notice how this is very similar to defining functions? The definition works in the same way. We start the class by using the keyword class and then the class name followed by a colon.
Indented and defined in the class is a variable we named x. We set x to 0. This is an attribute of the class; it is defined data for use later. We will get more into this (assigning values to attributes) in a later lesson, including why this is done and how it is used.
class PeopleCounter:
x = 0
def anotherOne(self) :
self.x = self.x + 1
print("So far",self.x)
Next we have declared a method and named it anotherOne
. Notice the method looks like a function, starting with the def
keyword, its name, and a colon. Its body consists of its own indented block of code. So, this class has one attribute (x
) and one method (.anotherOne()
).
One thing you may have noticed is the word self
in the method. Methods have a special first parameter that we name by convention self
.
self
is basically a variable that represents the instance of the class (the current object using it). By convention, we use the word self
only because it is almost an industry standard. You really can use anything in its place. However, most references to methods and search findings will typically have the word self
utilized. Plus, the name is close to what is actually happening. When we use self
, we can access the attributes and methods of a class.
Basically this .anotherOne()
method is taking the attribute x and adding 1 to it each time the method is called.
Using the Class
So, we defined a class called PeopleCounter
. What’s next? Does something happen if we run the code? No.
Just as the def
keyword does not cause function code to be executed, the class
keyword does not create an object. Instead, the class
keyword defines a template (remember blueprints) indicating what data and code will be contained in each object of the class PeopleCounter
. There are no executable lines of code so far in this program. Right now we just have the class defined with what attributes and methods we want the instances of this class to use.
Remember the cookie-cutter analogy we used earlier? We described a class as the cookie-cutter and what we create from it are cookies.
Now let’s take a look at how we can make a cookie from that cookie-cutter or, in this case, a people instance of the PeopleCounter
class that we defined above.
EXAMPLE
class PeopleCounter:
x = 0
def anotherOne(self) :
self.x = self.x + 1
print("So far",self.x)
people = PeopleCounter() # creation of an instance of the class PeopleCounter
people.anotherOne()
people.anotherOne()
people.anotherOne()
people.anotherOne()
If we were to run this code now, we would see the following output screen.
So far 1
So far 2
So far 3
So far 4
Let’s continue to break down this code—this time, the bottom half.
people = PeopleCounter() # creation of an instance of the class PeopleCounter
people.anotherOne()
people.anotherOne()
people.anotherOne()
people.anotherOne()
As we continue to look at this program, we see the first executable line of code.
people = PeopleCounter()
This is where we instruct Python to construct (i.e., create) an object/instance of the class PeopleCounter
. We chose to name the object created from PeopleCounter
people. It looks like a function call to the class itself. Python constructs the object with the right attributes (data) and methods (functions) and returns the object which is then assigned to our variable people
.
When the PeopleCounter
class is used to construct an object, the variable people
is used to point to that object. We use the variable people
to access the attributes and methods for that particular instance of the PeopleCounter
class.
Each PeopleCounter
object/instance contains within it a variable x
and a method named .anotherOne()
. We call the .anotherOne()
method on this line:
people.anotherOne()
Notice that we have now used the standard method call structure using the period (.) before the method name.
When the .anotherOne()
method is called, the first parameter of that method (remember self
) points to the particular instance of the PeopleCounter
class that .anotherOne()
method is called from (in our case, the people
instance).
Within the .anotherOne()
method, we see the line.
self.x = self.x + 1
This syntax using the dot (.
) operator is saying ‘the x within self.’ The .
(dot) operator connects the object (instance of a class) to the attributes and methods of that object. So for this first call to the method we have 0 = 0 + 1, so now x = 1. Each time the .anotherOne()
method is called, the internal x
value is incremented by 1 and the value is printed out.
Directions: Try adding the code below and see if you get the same results as we did above when running this defined class and instance calls.
class PeopleCounter:
x = 0
def anotherOne(self) :
self.x = self.x + 1
print("So far",self.x)
people = PeopleCounter() # creation of an instance of the class PeopleCounter
people.anotherOne()
people.anotherOne()
people.anotherOne()
people.anotherOne()
Attributes
Attributes are data defined in the class template and are the characteristics or properties of an object.
class
The class
keyword defines the data and code that will make up each of the objects. When defining a class, it starts with the class
keyword and is then followed by the name of the class and a colon.
.
The (.
) (dot) operator connects the object (instance of a class) to the attributes and methods of that object.
PeopleCounter
that included one attribute and one method.
Source: THIS CONTENT AND SUPPLEMENTAL MATERIAL HAS BEEN ADAPTED FROM “PYTHON FOR EVERYBODY” BY DR. CHARLES R. SEVERANCE ACCESS FOR FREE AT www.py4e.com/html3/ LICENSE: CREATIVE COMMONS ATTRIBUTION 3.0 UNPORTED.