In this chapter we'll learn about classes.
Python classes allow programmers to group data and information like variables and functions into a single organized unit.
Classes can be organized one to a file, or multiple classes that share similar types of functionality can be organized into the same file.
Classes allow us to share information with other classes and with other parts of a Python program.
Classes have features like inheritance which allow us to borrow from one class and use elements of that class to create another class.
Python also allows for multiple inheritance which allows a class to inherit attributes from multiple classes.
Python also allows for inherited or derived classes to override the base or parent classes, and all classes in Python are Objects.
The statements or information inside of a class are usually functions, but a class can also contain class variables that are specific to the class and usable throughout the entire class.
There are also variables called instance variables and those variables are specific to any Objects that are created by the class.
There are some features of a class which will require more explanation including:
The __init__
method, which allows every instance of a class to be created with specific parameters
The self
variable which allows information to be shared easily and efficiently.
In this lesson we'll learn about these different aspects of classes and we'll learn a basic class implementation.
The init method
The __init__
method allows every instance of a class to be created or initialized with specific parameters pre-determined at the creation of that Object.
What this does is sets the attributes for the Object, for example, the characteristics.
If I had a class for “Person”, I might want to set the person's first name and last name and perhaps a telephone number or an address.
The __init__
method has parameters that accept arguments which determine the attributes of the Object when it is created.
Once the parameters are given, those parameters are available to every class method.
The self
variable in Python represents an instance of a class, and specifically it references the instance of the class that has been created.
We use self
in order to make available all of the attributes to the methods throughout the class.
However, if a method is running as a part of the class rather than as an instance of the class, then we do not need to use the self
parameter in the method.
Let's create our own custom class.
We'll start by naming the class using the proper syntax.
Python classes always have the keyword class
followed by a space and the name of the class.
It's customary to capitalize the class name.
The words class and Person (in this case the class name) are followed by a colon — class Person:
.
The first method that we'll make in our class is the __init__
method.
This method allows us to create Objects that are members of the class. So, since we are making a Person
class, our __init__
method will allow us to create people later on.
In order to create people using this class, there are some things that we need to set up.
First, the __init__
method always, always, always has 2 underscores then the word “init” and then 2 more underscores.
This is followed by the parentheses which contain self
and the positional arguments that are characteristics of each person you want to create.
Let's go ahead and finish writing out the first line of the __init__
method.
Now I'll add a docstring that tells what this method does. This is a type of comment that is helpful for other programmers and it can be accessed in the future for people to understand what you've done.
class Person:
def __init__(self, firstname, lastname, health, status):
" initialize attributes to be used in/available for all \
class methods in this class, and for class Objects created \
by this class."
self.firstname = firstname
self.lastname = lastname
self.health = health
self.status = status
In order to be able to use the __init__
method, we need to create what are called the attributes.
The attributes are the characteristics that each Object can have. So, in this example, the attributes will be the characteristics of each person that we create — the first name, last name, health and status.
We'll assign each characteristic to the name self.
and then the name of the attributes.
The reason we assign each of the characteristics to a name that includes self
, is to allow us to make those characteristics available in our __init__
method as well as in the other methods.
You'll notice that every method that we have in the class has self
as the first argument, and this is the reason why.
Now that we've created our __init__
method, we'll write another method that will allow our people to introduce themselves.
What's cool about class methods, is that we only have to write this method once, but it can be used by every individual Object that we create with our class. So, if we make 1000 people, each of these people would be able to access this individual class and the methods in our class. So, we only need to write the code one time.
Let's try this with our introduce
method.
First, we'll write def
and the method name “introduce”.
Our introduce
method will be aligned with indentation with our __init__
method.
Now we will add a docstring to describe our method.
This function will be a simple function that when used will let each person that we create introduce themselves. It will use the first name and last name attributes from the __init__
method and those will be passed in through the self
argument.
def introduce(self):
"All people introduce themselves"
print("Hi, I'm {} {}.".format(self.firstname, self.lastname))
We'll write another class method that gives each person the ability to have an emotion.
The method will use the Python random
module and using that random
module we’ll assign an emotion to our person based on the random number that is chosen using conditional statements.
def emote(self):
emotion = random.randrange(1,3)
if emotion == 1:
print("{} is happy today".format(self.firstname))
elif emotion == 2:
print("{} is sad right now".format(self.firstname))
I've chosen a range of numbers between 0, 1, and 2, or between the ranges 1 and 3.
Finally, we'll make a method that prints a message based on the health score of the person that we create.
We'll print different messages for each score.
As I was writing out these status change positions, I realized that if somebody entered a health that was a little bit different than the exact amount, then they would get the “unconscious” message even if their health was 99, so I went ahead and changed the equivalencies so that way that they were more flexible.
I'm just going to add one more status.
def status_change(self):
if self.health == 100:
print("{} is totally healthy!".format(self.firstname))
elif self.health >=76:
print("{} is a little tired today.".format(self.firstname))
elif self.health >= 51:
print("{} feels unwell.".format(self.firstname))
elif self.health >= 40:
print("{} goes to the doctor".format(self.firstname))
else:
print("{} is unconscious.".format(self.firstname))
Okay, so when we run this code, we’ll have the opportunity to see if my changes worked.
We'll go ahead and test this out first by going all the way to the outer edge of indentation at the same level as the class that we created in the file and at that level, we will instantiate or make different people using this class.
We'll make Maria, Ray, and Lee. We'll give the class name Person
, and then you'll notice that the arguments come up to remind us of all the different attributes that are available for us to use and define.
I have given Maria a first name, last name, a health score and the status of being a friend to True.
Now let's create Rey. First name Rey, last name Jones, health status 88, friend status False.
Finally, Lee Williams, health score 72, friends status True.
Maria = Person("Maria", "Gutierrez", 95, status=True)
Rey = Person("Rey", "Jones", 88, status=False)
Lee = Person("Lee", "Williams", 72, status=True)
What we can do now is make a small test to see if we can correctly call the attributes for each of the people that we created.
First, we'll do that by printing the characteristics about each person.
So, I've made my print statement and I've called the first name and the status attributes of Maria.
print("{} is my friend? {}".format(Maria.firstname, Maria.status))
Go ahead and run this code and see what happens.
Maria is my friend, true. That's what I wanted to print, and first name came correctly, and the status of the friendship came correctly.
So, we'll try this now with Rey who has a different status than Maria to make sure that this is working the way we expect it to.
print("{} is my friend? {}".format(Rey.firstname, Rey.status))
This time, because I want to see the attributes associated with Rey, I'll call those attributes in my print function.
Let's try this code again.
Excellent.
The code is correctly calling the status and the name for each of the Objects or people that I've created using the class.
So, now we know that we can use the attributes that go along with each person we've created.
We also know that we can use the class methods to actually make our person.
Here's the beauty of the class methods.
We can use the instance variables and reuse the same code, but the code will be specific to each and every person we've created.
So, instead of needing to rewrite a method to introduce each of the people we've created, we can use our Person.introduce
method and replace “Person” with the name of the individual we've created.
The attributes of that individual will be used in the method. Let's see how this works with our 3 people.
We will call the introduce
method on each of the three people that we've created.
Maria.introduce()
Rey.introduce()
Lee.introduce()
Recall that our introduce
method gave a quote that each person would say, and inside of that quote, the person would use their own name. Here's our introduce method
, and it takes both the first name and takes the last name of the person.
So, even though we have three different people, we don't have to rewrite that code 3 different times.
Let's take a look at it run and see what the outcome is.
Excellent.
Each person has given a personal introduction and we've been able to apply the same class method to each individual Object with a differing result.
Let's try the health status method called “status_change”.
Maria.status_change()
Rey.status_change()
Lee.status_change()
You'll recall that we gave each of our people, Maria, Rey, and Lee, different health statuses. So, what we expect is that each of the statuses will print with a different message.
In accordance with the health status that Maria, Rey, and Lee each were assigned, a different message prints out.
Hopefully this helps to clarify what the class is, what the __init__
method does and how the self
helps us to use those attributes in each of the class methods, so we can reuse our class methods on every Object that we create with that class.