DEV Community

Cover image for OOP Python for Dummies
Jesse Ilc
Jesse Ilc

Posted on • Updated on

OOP Python for Dummies

~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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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'
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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>]
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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}"
Enter fullscreen mode Exit fullscreen mode

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'
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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>] 
Enter fullscreen mode Exit fullscreen mode

__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
Enter fullscreen mode Exit fullscreen mode

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)]
Enter fullscreen mode Exit fullscreen mode

satisfaction meme

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(takes self as argument).
Class methods:
functions that are bond to the class(takes cls 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")
Enter fullscreen mode Exit fullscreen mode

Sources

Top comments (0)