What is the difference between class and instance attributes?
Categories:
Class vs. Instance Attributes in Python: A Comprehensive Guide

Understand the fundamental differences between class and instance attributes in Python, how they are defined, accessed, and when to use each for effective object-oriented programming.
In Python's object-oriented programming paradigm, attributes are data associated with classes or objects. A common point of confusion for new developers is distinguishing between class attributes and instance attributes. While both store data, their scope, ownership, and behavior differ significantly. Understanding these differences is crucial for writing robust, efficient, and maintainable Python code.
What are Instance Attributes?
Instance attributes are unique to each object (instance) of a class. They are defined inside a class's methods, typically within the __init__
constructor, using the self
keyword. Each time a new object is created, it gets its own set of instance attributes, and changes to one instance's attributes do not affect other instances.
class Car:
def __init__(self, make, model, year):
self.make = make # Instance attribute
self.model = model # Instance attribute
self.year = year # Instance attribute
car1 = Car("Toyota", "Camry", 2020)
car2 = Car("Honda", "Civic", 2022)
print(f"Car 1: {car1.make} {car1.model} ({car1.year})")
print(f"Car 2: {car2.make} {car2.model} ({car2.year})")
car1.year = 2021 # Modifying car1's instance attribute
print(f"Car 1 (modified): {car1.year}")
print(f"Car 2 (unaffected): {car2.year}")
Defining and accessing instance attributes
What are Class Attributes?
Class attributes are shared by all instances of a class. They are defined directly within the class body, outside of any method. Class attributes belong to the class itself, not to any specific instance. This means that if you modify a class attribute, the change will be reflected across all instances of that class, unless an instance has its own instance attribute with the same name (which then shadows the class attribute for that specific instance).
class Dog:
species = "Canis familiaris" # Class attribute
def __init__(self, name, breed):
self.name = name
self.breed = breed
dog1 = Dog("Buddy", "Golden Retriever")
dog2 = Dog("Lucy", "Labrador")
print(f"Dog 1 species: {dog1.species}")
print(f"Dog 2 species: {dog2.species}")
print(f"Class species: {Dog.species}")
Dog.species = "Domestic Dog" # Modifying the class attribute
print(f"Dog 1 species (after modification): {dog1.species}")
print(f"Dog 2 species (after modification): {dog2.species}")
print(f"Class species (after modification): {Dog.species}")
dog1.species = "Wolf-like Dog" # This creates an instance attribute 'species' for dog1
print(f"Dog 1 species (instance attribute): {dog1.species}")
print(f"Dog 2 species (still class attribute): {dog2.species}")
print(f"Class species (unaffected by instance): {Dog.species}")
Defining and accessing class attributes, and shadowing
instance.class_attribute = value
), Python will create a new instance attribute with that name, effectively shadowing the class attribute for that specific instance, rather than modifying the class attribute itself. To modify the class attribute for all instances, always use the class name (e.g., ClassName.class_attribute = value
).Visualizing the Difference
The following diagram illustrates how class attributes are shared across all instances, while instance attributes are unique to each instance.
classDiagram class MyClass { +class_attribute: string +instance_attribute_1: string +instance_attribute_2: string +__init__(val1, val2) } MyClass "1" -- "*" Instance Instance : +instance_attribute_1 Instance : +instance_attribute_2 note for MyClass "class_attribute is shared by all instances" note for Instance "instance_attribute_1 and instance_attribute_2 are unique to each instance"
Class and Instance Attributes Relationship
When to Use Which?
Choosing between class and instance attributes depends on the nature of the data you want to store:
Use Instance Attributes when:
- The data is unique to each object.
- Each object needs its own state.
- Examples:
name
,age
,color
,price
,status
.
Use Class Attributes when:
- The data is common to all instances of a class.
- You need to store constants that apply to the entire class.
- You want to track a count of instances created.
- Examples:
species
,MAX_CAPACITY
,number_of_instances
.
class BankAccount:
interest_rate = 0.015 # Class attribute: shared by all accounts
account_count = 0 # Class attribute: tracks total accounts
def __init__(self, owner, balance=0):
self.owner = owner # Instance attribute: unique to each account
self.balance = balance # Instance attribute: unique to each account
BankAccount.account_count += 1 # Increment class attribute
def deposit(self, amount):
self.balance += amount
def withdraw(self, amount):
if self.balance >= amount:
self.balance -= amount
else:
print("Insufficient funds!")
acc1 = BankAccount("Alice", 1000)
acc2 = BankAccount("Bob")
print(f"Account 1 owner: {acc1.owner}, balance: {acc1.balance}, interest rate: {acc1.interest_rate}")
print(f"Account 2 owner: {acc2.owner}, balance: {acc2.balance}, interest rate: {acc2.interest_rate}")
print(f"Total accounts: {BankAccount.account_count}")
BankAccount.interest_rate = 0.02 # Change class attribute
print(f"New interest rate for acc1: {acc1.interest_rate}")
print(f"New interest rate for acc2: {acc2.interest_rate}")
Practical example using both class and instance attributes