The world’s leading publication for data science, AI, and ML professionals.

Practical Python: Class vs Instance Variables

How to define and interact with them

(image by author)
(image by author)

Class is the most fundamental piece of Python because it serves as the essence of object oriented Programming.

Everything in Python is an object such as integers, lists, dictionaries, functions and so on. Every object has a type and the object types are created using classes.

Instance is an object that belongs to a class. For instance, list is a class in Python. When we create a list, we have an instance of the list class.

In this article, I will focus on class and instance variables. I assume you have a basic knowledge about classes in Python. If not, you can still understand what class and instance variables are but the syntax might look a little overwhelming.

I have also written an introductory article about Python classes if you’d like to go over the basics.

Let’s start on class and instance variables.

Class variables are declared inside a class but outside of any function. Instance variables are declared inside the constructor which is the initmethod.

Consider the following class definition:

class Book():
   fontsize = 9
   page_width = 15
   def __init__(self, name, writer, length):
      self.name = name
      self.writer = writer
      self.length = length

Assume the Book class is used by a publishing company. The fontsize and page_width are class variables. Every book instance created will have a fontsize of 9 and page_width of 15 cm.

Photo by NMG Network on Unsplash
Photo by NMG Network on Unsplash

The name, writer, and length variables are declared in the init method so they are instance variables. The values of these variables are determined when creating an instance.

It makes sense because fontsize and page_width are usually standart. However, the name, writer, and lenght are specific to each book (i.e. instance).

It saves us a lot of time and effort to declare the fontsize and page_width as class variables. Assume the publishing company makes a decision to change the fontsize used in the books. If it was an instance variable, we would need to change it for each instance (i.e. book). However, since it is a class variable, one assignment will do the job for every book.

Let’s create an instance of the Book class:

book1 = Book("Intro to Python", "John Doe", 50000)
print(book1.writer)
"John Doe"
print(book1.page_width)
15

Although we did not explicitly assign the page_width variable to our instance, it has this attribute by default.

We can change the value of class variables for any instance (i.e. override them). Assume we want to make book1 a little wider so we will change the page_width of this instance.

book1.page_width = 17
print(book1.page_width)
17
print(Book.page_width)
15

As you can see, we only changed the value for book1 instance. The value of the class variable remained the same.

The methods we define can access the class variables but we need to be careful. I will show you the reason in the following example.

We define a method for the Book class that calculates the number of pages based on the length (in number of words), fontsize, and page_width:

def number_of_pages(self):
   pages = (self.length * fontsize) / (page_width * 100)
   return pages

This method will raise a NameError saying that ‘fontsize’ is not defined. Same goes for the ‘page_width’. Although these are class variables, we need to tell the method where to get them from.

We can get them from the instance itself or from the class.

#Using the instance
def number_of_pages(self):
   pages = (self.length * self.fontsize) / (self.page_width * 100)
   return pages
#Using the class
def number_of_pages(self):
   pages = (self.length * Book.fontsize) / (Book.page_width * 100)
   return pages

Both of these methods will work. Let’s do an example:

book1 = Book("Intro to Python", "John Doe", 50000)
book1_pages = book1.number_of_pages()
print(book1_pages)
300

Updating the class variables will affect all the instance of the class. It is a good feature that saves us time and effort. However, we also need to be careful about the extent of the changes.

Here is an example.

book1 = Book("Intro to Python", "John Doe", 50000)
book2 = Book("Intro to Pandas", "Jane Doe", 40000)
print(book1.fontsize, book2.fontsize)
(9, 9)
Book.fontsize = 11
print(book1.fontsize, book2.fontsize)
(11, 11)

The instances access the class variables through the class they belong to. Let’s do an example that shows what I mean.

The dict method can be used to see the attributes of an instance or class.

book1 = Book("Intro to Python", "John Doe", 50000)
print(book1.__dict__)
{'name': 'Intro to Python', 'writer': 'John Doe', 'length': 50000}
print(book1.fontsize)
9

When we print out the data attributes of book1, we do not see the fontsize or page_width. However, we can see that book1 has fontsize attribute by printing it out.

The instance (book1) accessed the class variables through the class. Let’s also apply the dict method on the Book class.

print(Book.__dict__)

module‘: ‘main‘, ‘fontsize’: 9, ‘page_width’: 15, ‘init‘: <function Book.init at 0x7f6cc5f54620>, ‘number_of_pages’: <function Book.number_of_pages at 0x7f6cc5f548c8>, ‘dict‘: <attribute ‘dict‘ of ‘Book’ objects>, ‘weakref‘: <attribute ‘weakref‘ of ‘Book’ objects>, ‘doc‘: None}

The class variables are printed out as well as the methods and some other stuff.


Conclusion

Class variables affect the entire class. Thus, when a class variable is updated, all the instances are updated. This comes in very handy but we also need to careful. If used carelessly, undesired consequences may occur.

Instance variables take unique values for each instance. We assign the values for them when creating the instance.

All the instances take the same value for class variables at first but we can update them for an instance later on. The changes we make on an instance do not affect the value of class variables for other instances.

Thank you for reading. Please let me know if you have any feedback.


Related Articles