Demystifying Class Variables In Python

Class variables are those variables which are independent of the object they are accessed from. Let’s understand this with an example.

class Animal:
     food_ids = [1,2,3]

In this class, I have initialised a variable with a default value. Let’s try to create some instances.

elephant = Animal()
snake = Animal()

As you can see, I have now created two instances of the same class. If I try to access the variable defined by the class from both objects, you can guess what the result would be.

print(elephant.food_ids) # prints [1,2,3]
print(snake.food_ids) # prints [1,2,3]

Well, that wasn’t magic. What happens if I append some value to one of the instance’s accessed variables?

snake.food_ids.append(4)
print(elephant.food_ids) # prints [1,2,3,4]
print(snake.food_ids) # prints [1,2,3,4]

Hmm..  I only appended some value to a variable using one of the instances, but it is reflected in both. There are two forces at play here:

  • food_ids was initialised with a default value while creating the class; therefore it was a class variable.
  • A list is a mutable object, meaning that I can change the values inside the list regardless of the initial values in the list.

This means if I use immutable objects like string or integer then this behaviour won’t be the same. If I directly replace the list with another list then also this won’t be replicated. Enough talk, let’s try another example.

snake.food_ids = [4]
print(elephant.food_ids) # prints [1,2,3]
print(snake.food_ids) # prints [4]

Why is this happening? If this was a class variable, then why can’t you replace the variable with an updated value across instances, Python? 😞

Before you start questioning your existence, let's try one other change. Voila!

Animal.food_ids = [4]
print(elephant.food_ids) # prints [4]
print(snake.food_ids) # prints [4]

Wait, what just happened?

Python manages separate dictionary-like objects to track the members/attributes of any instance and class. So, when we access the variable from the instance, Python checks if the variable exists in the instance’s dictionary-like object and if it does not exist then it checks the class’s dict-object.

Now in case, we were directly updating the variable from the class, it works because the original variable in the class is updated. But when we were updating the variable from the instance, Python made a new variable in the instance level with the same name.

For mutable objects like dictionary or list, when we use append or any other native operation of the data-structure, Python looks for the variable in the instance and when it does not find it, it uses the class variable to update the values. Therefore, we see this not-so-intuitive behavior.

Since self also points to the current instance of the class, the same behavior can be expected in the class if use methods to update values. Here's an example.

import random

class Animal:
    food_ids = [1,2,3]


    def some_method(self):
        self.food_ids.append(4) # class variable update
        self.food_ids = [random.randint(10,100)] # instance variable update

    def some_other_method(self):
        print(self.food_ids)


elephant = Animal()
snake = Animal()


elephant.some_method() # sets random value to food_ids
elephant.some_other_method() # prints list with single random value
snake.some_other_method() # prints [1,2,3,4], 4 being updated by elephant

This is really bizarre.

Resources

Kirti Gautam

I am a member of the Technical Staff at Fyle. I like to automate day to day stuff with code. I also love to watch thriller/mystery series.

More of our stories from

Engineering
Demystifying Class Variables In Python

Understanding class variables in python

Read more...
Interview Experience: Backend Engineering Internship at Fyle

Wanna know the secret to crack backend engineering interviews? Learn them here and intern at Fyle!

Read more...
The curse of being a Senior Engineer, how to deal with timelines, frustrations, etc

Being a good developer is 50% skill and 50% emotional support; here's my secret to balancing both at the right amount!

Read more...
How did I build cropping of receipts in the mobile app?

Follow Yash's journey of what it takes to reduce manual work for our customers when receipts come in all shapes and sizes!

Read more...
How did we increase Data Extraction accuracy by a whopping ~50%?

Wanna know the secret of data extraction, the complex machine learning models we use, the experiments we did? Read on...

Read more...
The not so secret sauce of my work

From chaos to clarity, follow Chethan's not so secret sauce to excelling at work!

Read more...
From Zero to Hero: The Policy Tests Journey!

The story of policy tests at Fyle

Read more...
How Fyle changed my life from a naive intern to a confident Engineering Lead

A blogpost that documents Shwetabh's journey at Fyle.

Read more...
Vikas Prasad @ Fyle

This document is a user guide to Vikas at work.

Read more...
Gokul K's README

This document is a user guide to Gokul at work.

Read more...

All Topics