How object and class attributes work

Andres Aristizabal
4 min readJan 12, 2021

If you are a Python programmer or are beginning to walk your way in this interpreted language, perhaps you have already come across two concepts typical of object-oriented languages: class attributes and object attributes.

Without a doubt, building classes and working with objects created from them is one of the most trivial tasks in object-oriented programming, even if you don’t believe it in Python everything is an object, an integer can be an instance of the class int, a string can be a instance of the class str and so on. But why is it important to know the difference between class and object attributes?

Differences between class and object attributes: let’s build a robot

To understand a concept well, there is nothing better than to see it in practice, in the next exercise we will build a class that will allow us to create instances of several robots, each with its attributes and methods.

class Robot:
"""I'll make for you a great robot"""
def __init__(self, name="Unknown"):
self.name = name

This class that we have written will allow us to create instances of it (objects) or robots for this specific case with a unique name for each one, let’s see …

class Robot:
"""I'll make for you a great robot"""
def __init__(self, name="Unknown"):
self.name = name
r1 = Robot("R2D2")
r2 = Robot("C3PO")
print("Robot r1: {} - Robot r2: {}".format(r1.name, r2.name))

Once we run this code, the output should look like this:

Robot r1: R2D2 - Robot r2: C3PO

Instance attributes

As you can see, two instances of our Robot class have been created, each one with a specific name, no matter how many robots we create, each one could have a different name thanks to its variable self.name, self refers to the instance on which we are acting on and name is nothing more than the name of the variable. It is important to note that variables in the context of a class are called attributes and those attributes that only have an effect within the object’s scope are called object attributes

Class attributes

Our robots have been assembled and are ready to receive our orders, but suppose that instead of two robots we had thousands more, it would be convenient to be able to know how many robots we have in our possession instantly, here the class attributes come into play, let’s continue refining our Robot class

class Robot:
"""I'll make for you a great robot"""

population = 0
def __init__(self, name="Unknown"):
self.name = name
type(self).population += 1
r1 = Robot("R2D2")
r2 = Robot("C3PO")
print("Robot r1: {} - Robot r2: {}".format(r1.name, r2.name))
print("Robot's population: {}".format(Robot.population))

As you can see we have added a new population variable just below the declaration of our class and unlike name, it does not contain the word self, what does this mean? Before giving you the answer, let’s look at the following output…

Robot r1: R2D2 - Robot r2: C3PO
Robot's population: 2

As we explained previously, the word self refers to the instance of the object on which we are acting, by omitting this we are declaring the variable under the scope of the class, this means that all robots can have access to it, helping us to carry an exact control of each instance that we create.

As a final requirement, let’s create a method to help us get old robots out of the way.

class Robot:
"""I'll make for you a great robot"""

population = 0
def __init__(self, name="Unknown"):
self.name = name
type(self).population += 1
def __del__(self):
Robot.population -= 1
print("It was a pleasure to serve you!")
r1 = Robot("R2D2")
r2 = Robot("C3PO")
print("Robot r1: {} - Robot r2: {}".format(r1.name, r2.name))
print("Robot's population: {}".format(Robot.population))
del r2
print("Robot's population: {}".format(Robot.population))
del r1
print("Robot's population: {}".format(Robot.population))

Now let’s try it and see what happens …

Robot r1: R2D2 - Robot r2: C3PO
Robot's population: 2
It was a pleasure to serve you!
Robot's population: 1
It was a pleasure to serve you!
Robot's population: 0

As you can see, we were able to keep track of the total robot population using our class attribute, now that you understand the difference there is only one question left to answer: how does Python handle this data internally?

Using the __dict__

Every object in Python has an attribute __dic__. This dictionary is used to store an object’s (writable) attributes. If we look closely, making use of this python attribute we can see the internal structure of any object.

class Robot:
def __init__(self, name):
self.name = name
r1 = Robot("R2D2")
print(Robot.__dict__)
print("\n------\n")
print(r1.__dict__)

let’s see what this code could generate…

{'__module__': '__main__', '__init__': <function Robot.__init__ at 0x1067e6790>, '__dict__': <attribute '__dict__' of 'Robot' objects>, '__weakref__': <attribute '__weakref__' of 'Robot' objects>, '__doc__': None}------{'name': 'R2D2'}

As you can see when using the __dic__ attribute on the class, it lists all the attributes that this class contains and if you look at the __dic__ of the object you will see the attribute that we have defined for it. This is the way Python organizes its information internally and thus shows us that definitely everything in Python is an object.

--

--