Scripting with Python is easy: you can do awesome things by writing some simple code. However, using only the most basic features has a problem: it is hard to scale. This doesn’t mean the application can’t handle a large set of data – it can. Instead, it means it can’t scale to a larger and larger codebase. In other words, you will end up having a messy file with spaghetti code if you don’t start using classes. In this Python Classes Tutorial, we are going to explain everything you need to understand the concepts of class, object, and instance. With this in mind, you will be soon creating awesome code.
Python Classes Tutorial: the basics
Before writing the code, we should have an idea of the theory. Read the following sections, and don’t worry if you are still confused. Once you get to the code, you will see everything coming together.
The need for Python Classes
Imagine you have to handle a file as we did in this article. You will need to open a file, read some content from it, maybe write something and then close it. Of course, Python already contains functions to handle files, but for this explanation imagine it doesn’t. You would need to create a function that opens the file, and returns a variable from which you can read and write from the file. Then, you could write some read
, write
and close
functions that accept that variable. Your functions will work like in the following snippet.
file_handler = open("filename.txt")
some_text = read(file_handler)
write(file_handler, "Some other text..")
close(file_handler)
At first glance, you might think everything is okay. It is, in fact, Python implements similar functions to handle files. However, functions heavily rely on the outer scope. The read
function will necessarily need a file handler, provided by the outer scope. And the same is true for the write
and close functions
. We can say the following about this code:
With functions, you separate the logic (the functions) from the data (the variables). However, you separate also the logic from the data it strictly needs in order to be functional.
In other words, our final goal here is to get some text from the file and write some other text to the file. However, we are also handling a file_handler
variable in our outer scope to do that, in order to do what we need.
Introducing Python Classes
With classes, we want to isolate the logic and the intermediary data it needs from the data. Thus, this is a valid definition for a Python class.
A class is the definition of an entity represented by its data and the logic that needs to work on that data.
So we can define a class to represent a file. It will contain all the functions that work on the file for reading, opening, and closing it. On top of that, it will also contain the data that these functions need to work, like the file handler. This way, you (the outer scope) will interface with the file class by providing only the strictly needed information. Instead of providing the file handler and some text, the write
function will need just the text.
At this point, we can introduce the concept of object.
An object, or instance, of a class is a variable that has the class as type.
We already know that a variable could be a string, an integer, a list, and so on. If its type is a class, then this variable is an object (or instance) of that class.
Python Classes Tutorial: an example
Instead of defining a class to handle files, we can define a class to handle subscribers. Imagine our application handles the subscriber to a newsletter, for example. Back in the old days, the definition of a subscriber could look something like this.
sub1 = { 'name': 'John', 'surname': 'Doe', 'mail': 'john.doe@example.com' }
For every subscriber, we would have to define the fields name
, surname
, and mail
.
Using a class
With a class, we could force the outer scope to provide this information. To define a class, we use the class
keyword.
class Subscriber:
def __init__(self, name, surname, mail):
self.name = name
self.surname = surname
self.mail = mail
Don’t get scared by this code. In the first line, we are just telling Python that the keyword Subscriber (capitalized) refers to a class. In the second line, we are defining the constructor function. This is the function that Python will call when we try to create an object from the Subscriber class. To do that, we can simply write the following code.
sub1 = Subscriber('John', 'Doe', 'john.doe@example.com')
This will execute the __init__
function of the Subscriber class, known as the constructor. Each class must have one, and only one. This is a special function, and you cannot use the return keyword
in it. Take a look at the previous snippet where we defined the constructor. It takes four parameters, the first being self
. In Python, self
is a special keyword that represents this very object (not this class).
Understanding “self” and attributes
This object can have attributes, that you can call by using a dot.
An attribute is a variable part of the class, and that can have a different value for each class instance.
So, in this case, the constructor takes three parameters and assign them to three attributes of the current object. Put the definition of the class in a file, and then add the following code below.
sub1 = Subscriber('John', 'Doe', 'john.doe@example.com')
sub2 = Subscriber('Jane', 'Doe', 'jane.done@example.com')
print(sub1.name)
print(sub2.name)
The output will be the following.
C:\Users\aless\Desktop>python myscript.py
John
Jane
This is because, in the class definition, self
acts somehow like a placeholder. For sub1
, means exactly sub1
; for sub2
it means sub2
. This way, the class definition is truly generic and can adapt every time to different data. Thus, the output of the name is different for our two subscribers, even if the code executed to set it was always self.name = name
.
Class Members
Besides attributes, classes can have members as well.
A member is a function that is part of a class, that will be executed in its instances.
We can expand our code as follows.
class Subscriber:
def __init__(self, name, surname, mail):
self.name = name
self.surname = surname
self.mail = mail
def recap(self):
return self.name + " " + self.surname + " <" + self.mail + ">"
sub1 = Subscriber('John', 'Doe', 'john.doe@example.com')
sub2 = Subscriber('Jane', 'Doe', 'jane.done@example.com')
print(sub1.recap())
print(sub2.recap())
In this case, our member function is recap
. It takes just one parameter, self. Just like the constructor, this simply tells Python the meaning of the self
keyword inside the function. You don’t need to pass it from outside. Furthermore, you need to have at least self
as a parameter for all member functions.
The member function will access object attributes through the self
keyword, just like the constructor. Thus, our code will output the following.
C:\Users\aless\Desktop>python myscript.py
John Doe <john.doe@example.com>
Jane Doe <jane.done@example.com>
Back to our file handler…
We started the article with the problem of a file handler. Using classes, accessing a file could look something like the following.
file = File('file.txt')
text = file.read()
file.write('Some other text')
file.close()
Of course, similar libraries already exist in Python, simply try a search on Google.
Wrapping it up
Best practices
Start working with Python the right way. Python programmers agree on conventions that tell how you should write the code (read this style guide for more info). However, we extracted the most significant points.
- The class name should be capitalized. In case the class name is two or more words, capitalize each word (like
MySampleClass
). - If the class name includes an uppercase acronym, you should write that all uppercase (like in
HTTPHandler
). - Members and attributes should have lowercase names, using underscores to separate more words (like normal functions and variables).
- If you want a member to be called from other members of the same class, but not from outside, start its name with an underscore.
- You should initialize all the attributes of a class to a value in the constructor.
- A class should represent a single entity. Classes like
Payer
andTeam
are okay, classes likePlayers
orHTTPAndFTPHandler
are not.
Python is an Object-Oriented Programming (OOP) language. This means that it was designed to specifically work with objects. Don’t be afraid and use that feature!
Conclusion
Mastering classes take time. The only thing that will help you is practicing, over and over. Try to rewrite some of your scripts using classes, or to solve basic problems with them. Here we have the most important points of this article.
- A class is the definition of logic and related data.
- An object or instance is a class with valorized data.
- An attribute is a variable defined in a class and tied to its objects.
- A member is a function defined in a class and tied to its objects.
- You can define a class with the
class
keyword. - To define the constructor, define the member
__init__
. - All members need to have
self
as a first parameter, including the constructor.
So, what are your thoughts on classes? How much time did you take to learn them? What were your challenges in that? What projects are you working on with them? Just let me know in the comments!