How to Use Class And Instance Variables in Python

Avatar

By squashlabs, Last Updated: September 29, 2023

How to Use Class And Instance Variables in Python

Introduction to Class and Instance Variables

Class and instance variables are two types of variables that are used in object-oriented programming languages like Python. They play a crucial role in defining the state and behavior of objects.

– Class variables are variables that are shared by all instances of a class. They are defined within the class but outside any methods. Class variables are accessed using the class name and can be modified by any instance of the class.

Example:

class Car:
    wheels = 4
    
    def __init__(self, color):
        self.color = color

# Accessing a class variable
print(Car.wheels)  # Output: 4

# Modifying a class variable
Car.wheels = 6
print(Car.wheels)  # Output: 6

# Creating instances of the class
car1 = Car("red")
car2 = Car("blue")

# Accessing a class variable through an instance
print(car1.wheels)  # Output: 6
print(car2.wheels)  # Output: 6

– Instance variables, on the other hand, are variables that belong to a specific instance of a class. They are defined within the class methods and are prefixed with the self keyword. Each instance of the class has its own copy of instance variables, and their values can vary between instances.

Example:

class Car:
    def __init__(self, color):
        self.color = color

# Creating instances of the class
car1 = Car("red")
car2 = Car("blue")

# Accessing instance variables
print(car1.color)  # Output: red
print(car2.color)  # Output: blue

# Modifying instance variables
car1.color = "green"
print(car1.color)  # Output: green
print(car2.color)  # Output: blue

In the next sections, we will explore the differences between class and instance variables, their use cases, best practices, real-world examples, performance considerations, advanced techniques, error handling, and provide code snippets for each topic.

Related Article: How to Use Python Super With Init Methods

Defining Class Variables

Class variables are defined within a class but outside any methods. They are shared by all instances of the class and can be accessed and modified using the class name.

Example:

class Car:
    wheels = 4
    fuel_type = "gasoline"
    
    def __init__(self, color):
        self.color = color

# Accessing a class variable
print(Car.wheels)  # Output: 4

# Modifying a class variable
Car.wheels = 6
print(Car.wheels)  # Output: 6

In the above example, the Car class has two class variables: wheels and fuel_type. These variables are shared by all instances of the class. You can access them using the class name, as shown in the code snippet.

Defining Instance Variables

Instance variables are defined within class methods and are prefixed with the self keyword. Each instance of the class has its own copy of instance variables.

Example:

class Car:
    def __init__(self, color):
        self.color = color

# Creating instances of the class
car1 = Car("red")
car2 = Car("blue")

# Accessing instance variables
print(car1.color)  # Output: red
print(car2.color)  # Output: blue

# Modifying instance variables
car1.color = "green"
print(car1.color)  # Output: green
print(car2.color)  # Output: blue

In the above example, the Car class has an instance variable color defined within the __init__ method. Each instance of the Car class has its own color attribute, which can be accessed and modified using the instance name, as shown in the code snippet.

The Difference Between Class and Instance Variables

The main difference between class and instance variables lies in their scope and accessibility.

– Class variables are shared by all instances of a class. They are defined outside any methods and can be accessed and modified using the class name. Any modification to a class variable affects all instances of the class.

Example:

class Car:
    wheels = 4
    
    def __init__(self, color):
        self.color = color

# Accessing a class variable through an instance
car1 = Car("red")
car2 = Car("blue")

print(car1.wheels)  # Output: 4
print(car2.wheels)  # Output: 4

# Modifying a class variable using the class name
Car.wheels = 6

print(car1.wheels)  # Output: 6
print(car2.wheels)  # Output: 6

– Instance variables, on the other hand, belong to a specific instance of a class. They are defined within class methods and are prefixed with the self keyword. Each instance of the class has its own copy of instance variables, and their values can vary between instances.

Example:

class Car:
    def __init__(self, color):
        self.color = color

# Creating instances of the class
car1 = Car("red")
car2 = Car("blue")

# Accessing instance variables
print(car1.color)  # Output: red
print(car2.color)  # Output: blue

# Modifying instance variables
car1.color = "green"
print(car1.color)  # Output: green
print(car2.color)  # Output: blue

In the above examples, the wheels variable is a class variable shared by all instances of the Car class. The color variable is an instance variable specific to each instance of the Car class.

Related Article: How to Determine the Type of an Object in Python

Class Variables: Use Case 1

One common use case for class variables is to store data that is shared among all instances of a class. For example, you might have a Car class that needs to keep track of the number of wheels for all cars.

Example:

class Car:
    wheels = 4
    
    def __init__(self, color):
        self.color = color

# Accessing a class variable through an instance
car1 = Car("red")
car2 = Car("blue")

print(car1.wheels)  # Output: 4
print(car2.wheels)  # Output: 4

# Modifying a class variable using the class name
Car.wheels = 6

print(car1.wheels)  # Output: 6
print(car2.wheels)  # Output: 6

In the above example, the wheels class variable stores the number of wheels for all instances of the Car class. By accessing and modifying the wheels variable through any instance or the class name, you can update the value for all instances.

Class Variables: Use Case 2

Another use case for class variables is to define constants or default values that are common to all instances of a class. For example, you might have a Person class with a class variable species that represents the species of all people.

Example:

class Person:
    species = "Homo sapiens"
    
    def __init__(self, name):
        self.name = name

# Creating instances of the class
person1 = Person("Alice")
person2 = Person("Bob")

# Accessing the class variable
print(person1.species)  # Output: Homo sapiens
print(person2.species)  # Output: Homo sapiens

In the above example, the species class variable stores the species name for all instances of the Person class. By accessing the species variable through any instance, you can retrieve the common species value.

Instance Variables: Use Case 1

One common use case for instance variables is to store unique data for each instance of a class. For example, you might have a Rectangle class that needs to store the width and height of each rectangle.

Example:

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height

# Creating instances of the class
rectangle1 = Rectangle(4, 5)
rectangle2 = Rectangle(3, 7)

# Accessing instance variables
print(rectangle1.width)  # Output: 4
print(rectangle1.height)  # Output: 5

print(rectangle2.width)  # Output: 3
print(rectangle2.height)  # Output: 7

In the above example, the width and height instance variables store the dimensions for each instance of the Rectangle class. Each instance has its own unique values for these variables.

Related Article: Python Super Keyword Tutorial

Instance Variables: Use Case 2

Another use case for instance variables is to track the state of an object. For example, you might have a BankAccount class that needs to store the balance and account holder name for each bank account.

Example:

class BankAccount:
    def __init__(self, account_number, account_holder):
        self.account_number = account_number
        self.account_holder = account_holder
        self.balance = 0.0

# Creating instances of the class
account1 = BankAccount("123456789", "Alice")
account2 = BankAccount("987654321", "Bob")

# Accessing and modifying instance variables
account1.balance = 1000.0
account2.balance = 500.0

print(account1.account_number)  # Output: 123456789
print(account1.account_holder)  # Output: Alice
print(account1.balance)  # Output: 1000.0

print(account2.account_number)  # Output: 987654321
print(account2.account_holder)  # Output: Bob
print(account2.balance)  # Output: 500.0

In the above example, the account_number, account_holder, and balance instance variables store the respective values for each instance of the BankAccount class. Each instance has its own unique values for these variables.

Best Practices: Class Variables

When working with class variables in Python, it is important to follow some best practices to ensure proper usage and maintainability of your code.

1. Use descriptive names: Choose meaningful names for your class variables to enhance code readability and maintainability. Avoid generic names that may cause confusion.

Example:

class Car:
    num_wheels = 4  # Good: Descriptive name

class Car:
    wheels = 4  # Bad: Generic name

2. Avoid mutable class variables: Class variables that are mutable (e.g., lists, dictionaries) can lead to unexpected behavior when modified by instances. Prefer immutable class variables or handle mutable class variables with caution.

Example:

class Car:
    colors = ["red", "blue", "green"]  # Mutable class variable

car1 = Car()
car2 = Car()

car1.colors.append("yellow")  # Modifying the class variable through an instance

print(car2.colors)  # Output: ['red', 'blue', 'green', 'yellow']

In the above example, modifying the colors class variable through car1 affects the colors value for all instances of the Car class.

3. Document class variables: Provide clear documentation for your class variables, including their purpose, expected values, and any constraints. This helps other developers understand and use your code correctly.

Example:

class Car:
    wheels = 4  # Represents the number of wheels for a car. Must be an integer.

Best Practices: Instance Variables

When working with instance variables in Python, it is important to follow some best practices to ensure proper usage and maintainability of your code.

1. Initialize instance variables in the constructor: It is recommended to initialize instance variables within the __init__ method of your class. This ensures that each instance starts with the desired initial values.

Example:

class Car:
    def __init__(self, color):
        self.color = color
        self.wheels = 4  # Initializing instance variable

car1 = Car("red")
print(car1.color)  # Output: red
print(car1.wheels)  # Output: 4

2. Use self-explanatory names: Choose descriptive names for your instance variables to enhance code readability and maintainability. The names should clearly indicate the purpose of the variable.

Example:

class Rectangle:
    def __init__(self, width, height):
        self.width = width  # Good: Descriptive name
        self.h = height  # Bad: Abbreviated name

3. Avoid shadowing class variables: Be cautious when using instance variables with the same name as a class variable. This can lead to unexpected behavior and confusion. Consider using different names or accessing the class variable explicitly.

Example:

class Car:
    wheels = 4
    
    def __init__(self, wheels):
        self.wheels = wheels  # Shadowing the class variable

car1 = Car(6)
print(car1.wheels)  # Output: 6

print(Car.wheels)  # Output: 4 (Accessing the class variable directly)

In the above example, the instance variable wheels shadows the class variable wheels. To access the class variable, you can use the class name.

Real World Example: Class Variables in Action

Let’s consider a real-world example of class variables in action. Suppose you are building a simple game that involves multiple players. Each player has a score, and you want to keep track of the highest score across all players.

Example:

class Player:
    high_score = 0
    
    def __init__(self, name):
        self.name = name
        self.score = 0
    
    def update_score(self, points):
        self.score += points
        if self.score > Player.high_score:
            Player.high_score = self.score

# Creating instances of the class
player1 = Player("Alice")
player2 = Player("Bob")

# Updating scores
player1.update_score(10)
player2.update_score(15)

print(player1.score)  # Output: 10
print(player2.score)  # Output: 15
print(Player.high_score)  # Output: 15

In the above example, the Player class has a class variable high_score that keeps track of the highest score across all players. Each player instance has its own instance variable score to store their individual scores. The update_score method updates the score of a player and also checks if the new score surpasses the current highest score. If so, it updates the high_score class variable. This allows all instances to access and update the highest score.

Real World Example: Instance Variables in Action

Let’s consider a real-world example of instance variables in action. Suppose you are building a simple online shopping system. Each product in the system has a name, price, and quantity available.

Example:

class Product:
    def __init__(self, name, price, quantity):
        self.name = name
        self.price = price
        self.quantity = quantity

# Creating instances of the class
product1 = Product("iPhone", 999.99, 10)
product2 = Product("iPad", 799.99, 5)

# Accessing instance variables
print(product1.name)  # Output: iPhone
print(product1.price)  # Output: 999.99
print(product1.quantity)  # Output: 10

print(product2.name)  # Output: iPad
print(product2.price)  # Output: 799.99
print(product2.quantity)  # Output: 5

In the above example, the Product class has instance variables name, price, and quantity. Each instance of the class represents a specific product with its own unique values for these variables. This allows you to store and access the relevant information for each product.

Performance Considerations: Class Variables

When using class variables, it is important to consider their impact on performance. Here are some performance considerations to keep in mind:

1. Shared state: Class variables introduce shared state among instances of a class. This can lead to unexpected behavior if multiple instances modify the same class variable simultaneously. Be cautious when relying on class variables for mutable shared state.

2. Memory usage: Class variables are shared among all instances of a class. If the class variable stores a large amount of data, it may consume significant memory. Consider the memory implications when using class variables, especially in scenarios with a large number of instances.

3. Access speed: Accessing class variables is generally faster than accessing instance variables because class variables are stored in a single location. However, the performance difference between class and instance variables is usually negligible unless you have specific performance-sensitive requirements.

4. Modifying class variables: Modifying class variables can impact the state of all instances. Ensure that modifications to class variables are intended and will not cause inconsistencies or unexpected behavior.

By considering these performance considerations, you can make informed decisions when using class variables in your code.

Performance Considerations: Instance Variables

When using instance variables, it is important to consider their impact on performance. Here are some performance considerations to keep in mind:

1. Memory usage: Each instance of a class has its own copy of instance variables. If the instance variables store a large amount of data, it may consume significant memory, especially when creating a large number of instances.

2. Access speed: Accessing instance variables is generally slightly slower than accessing class variables because instance variables are stored separately for each instance. However, the performance difference is usually negligible unless you have specific performance-sensitive requirements.

3. Modifying instance variables: Modifying instance variables affects the state of individual instances without impacting other instances. This can provide flexibility but may also require additional memory and computational resources if the modifications are frequent or involve complex data structures.

4. Encapsulation and readability: Proper usage of instance variables can enhance code encapsulation and readability by clearly associating data with specific instances. However, be mindful of creating too many instance variables, as it can lead to code complexity and reduced maintainability.

By considering these performance considerations, you can make informed decisions when using instance variables in your code.

Advanced Technique: Leveraging Class Variables

In addition to their basic usage, class variables can be leveraged for advanced techniques in Python. One such technique is using class variables as counters or trackers.

Example:

class Animal:
    total_count = 0
    
    def __init__(self, name):
        self.name = name
        Animal.total_count += 1

# Creating instances of the class
animal1 = Animal("Lion")
animal2 = Animal("Tiger")
animal3 = Animal("Elephant")

# Accessing the class variable
print(Animal.total_count)  # Output: 3

In the above example, the Animal class has a class variable total_count that keeps track of the total number of instances created. Each time a new instance is created, the total_count is incremented by 1 in the __init__ method. This allows you to easily keep count of the instances.

By leveraging class variables in advanced ways, you can add additional functionality and behavior to your classes.

Advanced Technique: Leveraging Instance Variables

Instance variables can be leveraged in advanced ways to enhance the functionality and behavior of your classes. One such technique is using instance variables for caching or memoization.

Example:

class Fibonacci:
    def __init__(self):
        self.cache = {0: 0, 1: 1}
    
    def get_fibonacci(self, n):
        if n in self.cache:
            return self.cache[n]
        
        result = self.get_fibonacci(n - 1) + self.get_fibonacci(n - 2)
        self.cache[n] = result
        return result

# Creating an instance of the class
fibonacci = Fibonacci()

# Calculating Fibonacci numbers
print(fibonacci.get_fibonacci(5))  # Output: 5
print(fibonacci.get_fibonacci(10))  # Output: 55

In the above example, the Fibonacci class uses an instance variable cache to store previously calculated Fibonacci numbers. When calculating a Fibonacci number, the instance checks if it is already available in the cache. If so, it returns the cached value. Otherwise, it calculates the Fibonacci number, stores it in the cache for future use, and returns the result. This improves performance by avoiding redundant calculations.

By leveraging instance variables in advanced ways, you can enhance the functionality and efficiency of your classes.

Code Snippet: Class Variables Definition

To define class variables in Python, you can assign values to them directly within the class definition. Class variables are typically defined outside any methods and are shared by all instances of the class.

class Car:
    wheels = 4
    fuel_type = "gasoline"

In the above code snippet, the Car class has two class variables: wheels and fuel_type. The wheels class variable is set to 4, representing the number of wheels for all cars. The fuel_type class variable is set to “gasoline”, representing the common fuel type for all cars.

Code Snippet: Instance Variables Definition

To define instance variables in Python, you can assign values to them within the class methods, typically within the __init__ method. Instance variables are prefixed with the self keyword and are specific to each instance of the class.

class Car:
    def __init__(self, color):
        self.color = color

In the above code snippet, the Car class has an instance variable color defined within the __init__ method. Each instance of the Car class can have a different color value assigned to its color instance variable.

Code Snippet: Class Variables Usage

To access and modify class variables in Python, you can use the class name followed by the variable name. Class variables are shared by all instances of the class.

class Car:
    wheels = 4
    
    def __init__(self, color):
        self.color = color

# Accessing a class variable
print(Car.wheels)  # Output: 4

# Modifying a class variable
Car.wheels = 6
print(Car.wheels)  # Output: 6

In the above code snippet, the wheels class variable is accessed and modified using the class name Car. The initial value of wheels is 4, and it is later modified to 6.

Code Snippet: Instance Variables Usage

To access and modify instance variables in Python, you can use the instance name followed by the variable name. Each instance of the class has its own copy of instance variables.

class Car:
    def __init__(self, color):
        self.color = color

# Creating instances of the class
car1 = Car("red")
car2 = Car("blue")

# Accessing instance variables
print(car1.color)  # Output: red
print(car2.color)  # Output: blue

# Modifying instance variables
car1.color = "green"
print(car1.color)  # Output: green
print(car2.color)  # Output: blue

In the above code snippet, the color instance variable is accessed and modified using the instance names car1 and car2. Each instance has its own unique value for the color instance variable.

Code Snippet: Class and Instance Variables Combined

In Python, you can combine class variables and instance variables within the same class. Class variables are shared by all instances, while instance variables are specific to each instance.

class Car:
    wheels = 4
    
    def __init__(self, color):
        self.color = color

# Accessing a class variable through an instance
car1 = Car("red")
car2 = Car("blue")

print(car1.wheels)  # Output: 4
print(car2.wheels)  # Output: 4

# Modifying a class variable using the class name
Car.wheels = 6

print(car1.wheels)  # Output: 6
print(car2.wheels)  # Output: 6

# Accessing and modifying an instance variable
print(car1.color)  # Output: red
print(car2.color)  # Output: blue

car1.color = "green"
print(car1.color)  # Output: green
print(car2.color)  # Output: blue

In the above code snippet, the Car class has both class variable wheels and instance variable color. The class variable is shared by all instances and can be accessed through any instance or the class name. The instance variable is specific to each instance and can be accessed and modified using the instance names.

Error Handling: Class Variables

When using class variables, it is important to handle potential errors or unexpected behavior that may arise. Here are some common error scenarios related to class variables:

1. Shadowing class variables: Be cautious when using instance variables with the same name as a class variable. Shadowing occurs when an instance variable masks or overrides a class variable with the same name. This can lead to unexpected behavior and confusion.

Example:

class Car:
    wheels = 4
    
    def __init__(self, wheels):
        self.wheels = wheels  # Shadowing the class variable

car1 = Car(6)
print(car1.wheels)  # Output: 6

print(Car.wheels)  # Output: 4 (Accessing the class variable directly)

In the above example, the instance variable wheels shadows the class variable wheels. To access the class variable, you can use the class name directly.

2. Unauthorized modifications: Class variables can be modified by any instance of the class. This can be both a benefit and a potential source of errors. Ensure that modifications to class variables are intended and will not cause inconsistencies or unexpected behavior.

Example:

class Car:
    wheels = 4

# Creating instances of the class
car1 = Car()
car2 = Car()

car1.wheels = 6  # Modifying the class variable through an instance

print(car2.wheels)  # Output: 4

In the above example, modifying the wheels class variable through the car1 instance does not affect the wheels value for other instances like car2. Each instance can modify the class variable independently.

By being aware of these potential error scenarios and handling them appropriately, you can ensure the correct usage of class variables in your code.

Error Handling: Instance Variables

When using instance variables, it is important to handle potential errors or unexpected behavior that may arise. Here are some common error scenarios related to instance variables:

1. Uninitialized instance variables: If you forget to initialize an instance variable within the __init__ method or assign a value to it later, accessing the uninitialized instance variable will result in an AttributeError.

Example:

class Car:
    def __init__(self, color):
        self.color = color

# Creating instances of the class
car1 = Car("red")
car2 = Car("blue")

print(car1.wheels)  # Error: AttributeError: 'Car' object has no attribute 'wheels'

In the above example, the wheels instance variable is not defined within the __init__ method or assigned a value later. Accessing it will raise an AttributeError.

2. Misspelled instance variables: If you misspell the name of an instance variable when accessing or modifying it, Python will create a new instance variable with the misspelled name instead of using the existing one. This can lead to unintended behavior and bugs.

Example:

class Car:
    def __init__(self, color):
        self.color = color

# Creating instances of the class
car1 = Car("red")

print(car1.colour)  # Error: AttributeError: 'Car' object has no attribute 'colour'

In the above example, the correct instance variable name is color, but it is misspelled as colour when accessing it. This results in an AttributeError.