~For my TLDR people skip to TLDR (last section)~
Introduction
As beginner programmers, there's a substantial amount of information we need to learn and absorb. And I mean a SUBSTANTIAL amount. On top of the basic fundamentals etc., we also encounter different programming paradigms.
Programming Paradigms
"Programming paradigms are different ways or styles in which a given program or programming language can be organized."
-freecodecamp.org -- Germán Cocca
A popular paradigm, one that I'm sure many of you have heard before, is Object-Oriented Programming or OOP for short. If you've ever watched a Python youtube tutorial, you'll know exactly what I'm talking about. OOP has become quite popular due to its ability to organize code, enhance reusability, and improve maintainability.
Object-Oriented Programming
"In basic terms, OOP is a programming pattern that is built around objects or entities, so it's called object-oriented programming."
-freecodecamp.org -- Hillary Nyakundi
So, let's not waste your time and dive right in.
Defining a class
To start using OOP structure in Python we first need to define a class
. To do this, first type class
, followed by what we want to name our class
, followed by colons. Here's what that looks like:
class ClassName:
# Class attributes/constants
# Instance attributes
# Constructor __init__
# Instance and Class methods
Now that we know how to define a class
let's talk about what goes into the class
.
__init__
Constructor
In order to properly instantiate(create) objects of our class
(hence where OOP comes from), we're going to need to define a method called __init__
. This method is known as a constructor and it allows us to initialize object attributes and perform any setup required for our class
. Here's what that looks likes:
class VideoGame:
# Class attributes/constants
def __init__(self, game, system)
# Instance attributes
# Instance and Class methods
In the example above, I created a class
called VideoGame
which we're going to build upon.
self
is referring to the instance of our class
. Meaning it's referring to the instance object we're creating.
game
and system
are instance attributes. These are variables that are bound to the instance object itself. We'll dive deeper into this in the next section.
Instance Attributes
Now that we've defined our class
and added our __init__
method, we can start adding some instance attributes. Here's what that looks like:
class VideoGame:
# Class attributes/constants
def __init__(self, game, system):
self.game = game
self.system = system
# Instance and Class methods
When we instantiate an object to our class
, we're going to pass in parameters to match our instance attributes. So in this case, we would pass 2 parameters (game
and system
) which will be bound to that instance object. Instantiating an object looks something like this:
# instantiate
game1 = VideoGame("TOTK", "Switch")
# view our game object
game1
# => <__main__.VideoGame object at 0x7f39496ae390>
game1.game
# => 'TOTK'
game1.system
# => 'Switch'
Here, we call VideoGame
and pass in our 2 parameters which correlate to game
and system
. We assign this to a variable so we can access it's elements.
When we type game1
, it returns the instance object. We can change this by using the function __repr__
to return something that human's can actually understand. I will cover this in the instance/class methods section.
When we type game1.game
and game1.system
, it returns our object's game
and system
that we instantiated respectively.
Class Attributes
Before we move on, let's talk about class attributes. These refer to variables that are shared between all instance object's of the class
. This differs from instance attributes which are accessed only by the instance objects. Let's add a class variable to our class
:
class VideoGame:
games = []
def __init__(self, game, system):
self.game = game
self.system = system
# Instance and Class methods
Here I made an empty list for the entire class
. Let's add our instance objects to this list for future reference:
class VideoGame:
games_list = []
def __init__(self, game, system):
self.game = game
self.system = system
VideoGame.games_list.append(self)
# Instance and Class methods
Now everytime we instantiate a new object, it'll be added to games_list
. We can call games_list
by typing VideoGame.games_list
which will return a list of all instance objects in VideoGame
. Right now it'll look something like this until we add the __repr__
function:
# instantiate object
game1 = VideoGame("TOTK", "Switch")
VideoGame.games_list
# => [<__main__.VideoGame object at 0x7f555c9467d0>]
Class Constants
Class constants are almost identical to class attributes. The key differences are that class constants are used to store data that doesn't change and the syntax used to define them requires all uppercase. Let's say for example our class
only takes 3 options for systems; Xbox
, Playstation
, Switch
. If the user tries to add a game from any other system it won't add it unless it's from our 3. Let's define a class constant with these systems and we'll write out our check_systems
method later in class methods:
class VideoGame:
# SYSTEMS_LIST = ["Xbox", "Playstation", "Switch"]
games_list = []
def __init__(self, game, system):
# if self.check_system(system)
self.game = game
self.system = system
VideoGame.games_list.append(self)
# Instance and Class methods
Let's move on to methods.
Instance methods
Instance methods are basically functions that you can call on any object within the class
. Let's write 2 instance methods that will start our game and close our game:
class VideoGame:
games_list = []
def __init__(self, game, system):
self.game = game
self.system = system
VideoGame.games_list.append(self)
def open_game(self):
return f"Booting {self.game} on the {self.system}"
def close_game(self):
return f"Closing {self.game} on the {self.system}"
Let's see what happens when we call these methods on a instance object:
# Instantiate object
game1 = VideoGame("TOTK", "Switch")
# Call our methods
game1.open_game()
# => 'Booting TOTK on the Switch'
game1.close_game()
# => 'Closing TOTK on the Switch'
After calling our instance methods(functions) they run on our instance objects. Our instance methods are very basic and just return an object's game
and system
however, these instance methods work like functions, which means they can be much more complex and take in additional parameters.
Class methods
Class methods are extremely similar to instance methods. The key differences are class methods refer to the class
and not the instance object; also the syntax is different. If you recall our class constant from earlier SYSTEMS_LIST
we can add a class method that checks if our object's system
matches a system
in our list. If it matches, we add the game to our list, otherwise we won't:
class VideoGame:
SYSTEMS_LIST = ["Xbox", "Playstation", "Switch"]
games_list = []
def __init__(self, game, system):
if self.check_system(system):
self.game = game
self.system = system
VideoGame.games_list.append(self)
# instance methods
@classmethod
def check_system(cls, system):
return system in cls.SYSTEMS_LIST
To define a class method we first need to include @classmethod
above our function. Instead of self
(used for instance methods) we use cls
(refers to the class
) in our parameters. We also passed system
from our instance object to see if it's in our list. If done correctly only objects with systems from our list will added:
# Instantiate objects
game1 = VideoGame("TOTK", "Switch")
game2 = VideoGame("MH World", "Playstation")
game3 = VideoGame("Metal Gear Rising", "PC")
VideoGame.games_list
# => [<__main__.VideoGame object at 0x7f8790df6e50>, <__main__.VideoGame object at 0x7f8790df6e90>]
__repr__
Function
Okay, let's finally talk about __repr__
. In the code above I have no idea what <__main__.VideoGame object at 0x7f8790df6e50>
points too. If you do, that's great, but let's translate this into something regular humans can read. The syntax is very close to the __int__
method:
class VideoGame:
# Class constants
# Class variables
def __init__(self, game, system):
if self.check_system(system):
self.game = game
self.system = system
VideoGame.games_list.append(self)
def __repr__(self):
# '+\' combines our lines together
return f"Game(game={self.game}, " +\
f"system={self.system})"
# Instance methods
# Class Methods
The parameter we pass is self
and the function will return a string with our instance object's game
and system
. Now instead of returning the instance object itself we get something that's readable:
# Instantiate objects
game1 = VideoGame("TOTK", "Switch")
game2 = VideoGame("MHW", "Playstation")
game3 = VideoGame("Metal Gear Rising", "PC")
VideoGame.games_list
# => [Game(game=TOTK, system=Switch), Game(game=MHW, system=Playstation)]
Conclusion
OOP can be daunting at first, with all it's new vocabulary. In theory everything sounds so simple but in practice it's a whole nother story. I hope this read helped you out a little bit to better understand OOP in Python. If you want to see a short summary of everything you can read the TLDR section. Happy coding!
TLDR
~Key Vocab~
Python class:
a blueprint or template for creating objects (instances).
Instance Object:
a specific occurrence of a class.
Instantiate:
another word for create.
Class Attributes:
varibales bound to the class. Accessible to all instances.
Class Constants:
varibales bound to the class(data cannot be changed).
Constructor__init__
:
used to initialize objects attributes and perform other set up.
Instance Attributes:
variables bound to the instance.
__repr__
Function:
a function that makes instance objects readable.
Instance Methods:
functions that are bond to the instance(takesself
as argument).
Class methods:
functions that are bond to the class(takescls
as argument).
~Example~
# Python class
class VideoGame:
# Class Constants
SYSTEMS_LIST = ["Xbox", "Playstation", "Switch"]
# Class Attributes (All instance objects in class can access)
games_list = []
# Constructor (initialize Object Attributes and other set up)
def __init__(self, game, system):
# Refers to Class Method check_system
if self.check_system(system):
# Instance Attributes
self.game = game
self.system = system
#adds to game_list Class Attribute
VideoGame.games_list.append(self)
# Makes Instance Object's readable
def __repr__(self):
return f"Game(game={self.game}, " +\
f"system={self.system})"
# Instance Methods
def open_game(self):
return f"Booting {self.game} on the {self.system}"
def close_game(self):
return f"Closing {self.game} on the {self.system}"
# Class methods
@classmethod
def check_system(cls, system):
return system in cls.SYSTEMS_LIST
# Instantiate objects
game1 = VideoGame("TOTK", "Switch")
game2 = VideoGame("MHW", "Playstation")
# Omitted from game_list due to system (refer to check system)
game3 = VideoGame("Metal Gear Rising", "PC")
Sources
- https://www.freecodecamp.org/news/an-introduction-to-programming-paradigms/
- https://www.freecodecamp.org/news/what-is-object-oriented-programming/
- https://towardsdatascience.com/practical-python-class-vs-instance-variables-431fd16430d
- https://www.ibm.com/docs/en/spss-modeler/saas?topic=programming-defining-class-attributes-methods
- https://www.programiz.com/python-programming/methods/built-in/classmethod#:~:text=A%20class%20method%20is%20a,just%20deals%20with%20the%20parameters
- https://python-course.eu/oop/class-instance-attributes.php
- https://www.programiz.com/python-programming/methods/built-in/repr
- https://betterdatascience.com/python-constants/
Top comments (0)