Bird
Raised Fist0
Pythonprogramming~15 mins

Class attributes in Python - Deep Dive

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Overview - Class attributes
What is it?
Class attributes are variables that belong to the class itself, not to any one object created from the class. They are shared by all instances of the class, meaning every object can access the same value. This is different from instance attributes, which are unique to each object. Class attributes help store information common to all objects of that class.
Why it matters
Without class attributes, every object would need to store its own copy of common data, wasting memory and making updates harder. Class attributes let programmers keep shared data in one place, making code simpler and more efficient. They also help organize information logically, like counting how many objects have been created or setting default values for all objects.
Where it fits
Before learning class attributes, you should understand basic classes and instance attributes in Python. After mastering class attributes, you can explore advanced topics like class methods, static methods, and metaclasses, which build on how classes manage data and behavior.
Mental Model
Core Idea
Class attributes are shared variables stored once in the class, accessible by all instances, unlike instance attributes which belong to each object separately.
Think of it like...
Imagine a classroom where the teacher writes the class rules on the board (class attribute). Every student (object) sees the same rules on the board, instead of each student having their own copy of the rules.
┌─────────────┐
│   Class     │
│ ┌─────────┐ │
│ │shared   │ │
│ │attribute│ │
│ └─────────┘ │
└─────┬───────┘
      │
 ┌────┴─────┐
 │ Instance │
 │ objects  │
 └──────────┘
All instances access the same class attribute stored in the class.
Build-Up - 7 Steps
1
FoundationUnderstanding classes and instances
🤔
Concept: Learn what classes and instances are and how instance attributes work.
In Python, a class is like a blueprint for creating objects. Each object (instance) can have its own data called instance attributes. For example: class Dog: def __init__(self, name): self.name = name # instance attribute my_dog = Dog('Buddy') print(my_dog.name) # Output: Buddy
Result
The program prints 'Buddy', showing each object has its own name.
Understanding that instance attributes belong to each object individually sets the stage to see how class attributes differ by being shared.
2
FoundationIntroducing class attributes
🤔
Concept: Learn how to define variables that belong to the class itself, shared by all instances.
Class attributes are defined directly inside the class, outside any methods: class Dog: species = 'Canis familiaris' # class attribute def __init__(self, name): self.name = name # instance attribute print(Dog.species) # Access via class my_dog = Dog('Buddy') print(my_dog.species) # Access via instance
Result
Output: Canis familiaris Canis familiaris
Knowing that class attributes can be accessed both from the class and instances shows their shared nature.
3
IntermediateModifying class attributes
🤔Before reading on: If you change a class attribute via one instance, do you think it changes for all instances or just that one? Commit to your answer.
Concept: Understand how changing class attributes affects all instances and how instance attributes can override them.
Changing a class attribute via the class changes it for all instances: class Dog: species = 'Canis familiaris' def __init__(self, name): self.name = name Dog.species = 'Canis lupus' dog1 = Dog('Buddy') dog2 = Dog('Max') print(dog1.species) # Canis lupus print(dog2.species) # Canis lupus # But setting the attribute on an instance creates an instance attribute: dog1.species = 'Unknown' print(dog1.species) # Unknown print(dog2.species) # Canis lupus
Result
Changing class attribute via class affects all instances; setting on instance creates a separate instance attribute.
Understanding the difference between modifying class attributes on the class vs. on instances prevents bugs where shared data unexpectedly changes or is shadowed.
4
IntermediateUsing class attributes for shared counters
🤔Before reading on: How would you count how many objects of a class have been created? Guess the best place to store this count.
Concept: Use class attributes to keep track of data shared across all instances, like counting how many objects exist.
You can use a class attribute as a counter: class Dog: count = 0 # class attribute to count instances def __init__(self, name): self.name = name Dog.count += 1 # increment count when new object created print(Dog.count) # 0 dog1 = Dog('Buddy') dog2 = Dog('Max') print(Dog.count) # 2
Result
The count increases as new objects are created, showing shared state.
Knowing class attributes can hold shared state like counters helps design classes that track global information efficiently.
5
AdvancedClass attributes vs instance attributes lookup
🤔Before reading on: When accessing an attribute on an instance, do you think Python looks at instance attributes first or class attributes first? Commit your answer.
Concept: Learn the attribute lookup order Python uses when accessing attributes on instances and classes.
When you access an attribute on an instance, Python first looks for it in the instance's own attributes. If not found, it looks in the class attributes: class Dog: species = 'Canis familiaris' def __init__(self, name): self.name = name dog = Dog('Buddy') print(dog.name) # Found in instance print(dog.species) # Not in instance, found in class # If you set dog.species = 'Unknown', it creates an instance attribute that shadows the class attribute.
Result
Python finds instance attributes first, then class attributes if needed.
Understanding attribute lookup order is key to debugging why some attributes appear to change unexpectedly or why class attributes seem overridden.
6
AdvancedClass attributes and inheritance behavior
🤔Before reading on: If a subclass changes a class attribute, does it affect the parent class or only the subclass? Predict before reading.
Concept: Explore how class attributes behave with inheritance and how subclasses can override or share them.
Subclasses inherit class attributes but can override them: class Animal: kingdom = 'Animalia' class Dog(Animal): pass print(Dog.kingdom) # Animalia Dog.kingdom = 'Canis' print(Dog.kingdom) # Canis print(Animal.kingdom) # Animalia # Changing subclass attribute does not affect parent class attribute.
Result
Subclass can override class attributes without changing parent class's attribute.
Knowing how inheritance affects class attributes helps design class hierarchies that share or customize data properly.
7
ExpertClass attributes and mutable shared state pitfalls
🤔Before reading on: If a class attribute is a list, and one instance modifies it, do you think other instances see the change? Commit your answer.
Concept: Understand the risks of using mutable objects as class attributes and how it can cause unexpected shared state changes.
Class attributes that are mutable (like lists or dictionaries) are shared by all instances. Modifying them from one instance affects all: class Dog: tricks = [] # class attribute list def add_trick(self, trick): self.tricks.append(trick) dog1 = Dog() dog2 = Dog() dog1.add_trick('roll over') print(dog2.tricks) # ['roll over'] # Both instances share the same list, which can cause bugs. # To avoid this, use instance attributes for mutable data: class Dog: def __init__(self): self.tricks = [] # instance attribute def add_trick(self, trick): self.tricks.append(trick)
Result
Mutable class attributes cause shared changes across instances, often unintended.
Recognizing mutable class attribute pitfalls prevents subtle bugs where one object's changes affect others unexpectedly.
Under the Hood
Python stores class attributes in the class's __dict__ dictionary. When you access an attribute on an instance, Python first checks the instance's __dict__. If not found, it looks up the class's __dict__ and then up the inheritance chain. Class attributes live once in the class object, so all instances share the same reference. Mutable class attributes point to the same object, so changes affect all instances.
Why designed this way?
This design allows efficient memory use by sharing common data and behavior across instances. It also supports inheritance and polymorphism by letting subclasses override or extend class attributes. Alternatives like copying attributes to each instance would waste memory and complicate updates. The lookup order balances flexibility and performance.
Instance attribute lookup flow:

┌───────────────┐
│   Instance    │
│  __dict__     │
│ (instance vars)│
└──────┬────────┘
       │ if not found
       ▼
┌───────────────┐
│    Class      │
│  __dict__     │
│(class attrs)  │
└──────┬────────┘
       │ if not found
       ▼
┌───────────────┐
│  Parent Class │
│  __dict__     │
│(inherited attrs)│
└───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: If you change a class attribute via one instance, does it change for all instances? Commit yes or no.
Common Belief:Changing a class attribute via an instance changes it for all instances.
Tap to reveal reality
Reality:Changing a class attribute via an instance creates a new instance attribute for that object only, leaving the class attribute and other instances unchanged.
Why it matters:Believing this causes confusion when changes seem local but are expected to be global, leading to bugs where shared data is not updated.
Quick: Are class attributes copied to each instance when created? Commit yes or no.
Common Belief:Class attributes are copied to each instance when the object is created.
Tap to reveal reality
Reality:Class attributes are stored only once in the class and accessed by instances via lookup; they are not copied to each instance.
Why it matters:Misunderstanding this leads to incorrect assumptions about memory use and attribute behavior, causing inefficient or buggy code.
Quick: If a class attribute is a list, does modifying it from one instance affect others? Commit yes or no.
Common Belief:Each instance has its own copy of mutable class attributes like lists.
Tap to reveal reality
Reality:Mutable class attributes are shared by all instances; modifying them from one instance affects all instances.
Why it matters:This misconception causes bugs where one object's changes unexpectedly affect others, leading to hard-to-find errors.
Quick: Does changing a subclass's class attribute always change the parent class's attribute? Commit yes or no.
Common Belief:Changing a subclass's class attribute changes the parent class's attribute too.
Tap to reveal reality
Reality:Changing a subclass's class attribute only affects the subclass; the parent class's attribute remains unchanged.
Why it matters:Believing otherwise can cause confusion in inheritance hierarchies and incorrect assumptions about shared data.
Expert Zone
1
Class attributes are stored in the class's __dict__, but descriptors or properties can customize attribute access, affecting how class attributes behave.
2
Mutable class attributes can be safely shared if they are treated as read-only or carefully managed with methods that avoid unintended side effects.
3
Using class attributes with metaclasses or dynamic class creation allows powerful patterns like automatic registration or configuration sharing.
When NOT to use
Avoid using class attributes for data that should be unique per instance, especially mutable data. Instead, use instance attributes initialized in __init__. For thread-safe or concurrent environments, avoid mutable shared class attributes or protect them with synchronization.
Production Patterns
Class attributes are commonly used for constants, default configuration values, counters, and caches shared across instances. They are also used in frameworks to define metadata or register subclasses automatically. Proper use avoids duplication and centralizes shared data.
Connections
Instance attributes
Complementary concepts in object-oriented programming
Understanding class attributes alongside instance attributes clarifies how data is organized between shared and unique parts of objects.
Inheritance
Class attributes participate in inheritance and can be overridden by subclasses
Knowing how class attributes behave in inheritance helps design flexible and maintainable class hierarchies.
Shared memory in operating systems
Similar pattern of shared data accessible by multiple processes or threads
Recognizing class attributes as shared memory helps understand risks of concurrent modification and the need for careful management.
Common Pitfalls
#1Using mutable class attributes for per-instance data causes shared state bugs.
Wrong approach:class Dog: tricks = [] # mutable class attribute def add_trick(self, trick): self.tricks.append(trick) dog1 = Dog() dog2 = Dog() dog1.add_trick('roll over') print(dog2.tricks) # Unexpectedly ['roll over']
Correct approach:class Dog: def __init__(self): self.tricks = [] # instance attribute def add_trick(self, trick): self.tricks.append(trick) dog1 = Dog() dog2 = Dog() dog1.add_trick('roll over') print(dog2.tricks) # []
Root cause:Misunderstanding that mutable class attributes are shared references, not copied per instance.
#2Trying to change a class attribute via an instance expecting it to update for all instances.
Wrong approach:class Dog: species = 'Canis familiaris' dog1 = Dog() dog2 = Dog() dog1.species = 'Unknown' # This creates instance attribute print(dog2.species) # Still 'Canis familiaris', not 'Unknown'
Correct approach:Dog.species = 'Unknown' # Change class attribute directly print(dog2.species) # 'Unknown'
Root cause:Confusing instance attribute assignment with class attribute modification.
#3Assuming class attributes are copied to instances causing unexpected memory use.
Wrong approach:class Dog: species = 'Canis familiaris' # Believing each instance has its own copy of species attribute
Correct approach:class Dog: species = 'Canis familiaris' # Stored once in class # Instances access shared attribute via lookup
Root cause:Lack of understanding of Python's attribute lookup mechanism.
Key Takeaways
Class attributes are variables stored once in the class and shared by all instances, unlike instance attributes which belong to each object separately.
Accessing an attribute on an instance first checks instance attributes, then class attributes if not found, explaining how instance attributes can override class attributes.
Modifying a class attribute via the class changes it for all instances, but assigning to it via an instance creates a new instance attribute, leaving the class attribute unchanged.
Using mutable objects as class attributes can cause unexpected shared state changes across instances, so mutable data should usually be stored in instance attributes.
Class attributes participate in inheritance and can be overridden by subclasses, enabling flexible and maintainable class hierarchies.

Practice

(1/5)
1. What is a class attribute in Python?
class Car:
wheels = 4
Here, what does wheels represent?
easy
A. A value shared by all Car objects
B. A value unique to each Car object
C. A method inside the Car class
D. A variable defined inside a method

Solution

  1. Step 1: Identify the attribute location

    The attribute wheels is defined inside the class but outside any method.
  2. Step 2: Understand class attribute behavior

    Attributes defined this way are shared by all instances of the class.
  3. Final Answer:

    A value shared by all Car objects -> Option A
  4. Quick Check:

    Class attribute = shared value [OK]
Hint: Class attributes are outside methods, shared by all instances [OK]
Common Mistakes:
  • Thinking class attributes are unique per object
  • Confusing class attributes with instance attributes
  • Assuming class attributes are methods
2. Which of the following is the correct way to define a class attribute color with value "red" inside a class Fruit?
easy
A. class Fruit: def __init__(self): color = "red"
B. class Fruit: def color(self): return "red"
C. class Fruit: def __init__(self, color): self.color = color
D. class Fruit: color = "red"

Solution

  1. Step 1: Identify class attribute syntax

    A class attribute is defined directly inside the class, outside any method.
  2. Step 2: Check each option

    class Fruit: color = "red" correctly defines color as a class attribute. class Fruit: def __init__(self): color = "red" defines a local variable inside __init__. class Fruit: def color(self): return "red" defines a method, not an attribute. class Fruit: def __init__(self, color): self.color = color defines an instance attribute.
  3. Final Answer:

    class Fruit: color = "red" -> Option D
  4. Quick Check:

    Class attribute = direct assignment inside class [OK]
Hint: Class attributes are assigned directly inside class, outside methods [OK]
Common Mistakes:
  • Defining attribute inside __init__ without self
  • Confusing methods with attributes
  • Using self for class attributes
3. What will be the output of this code?
class Dog:
    species = "Canine"

dog1 = Dog()
dog2 = Dog()
Dog.species = "Wolf"
print(dog1.species)
print(dog2.species)
medium
A. Canine\nCanine
B. Wolf\nCanine
C. Wolf\nWolf
D. Canine\nWolf

Solution

  1. Step 1: Understand class attribute change

    The attribute species is a class attribute shared by all instances.
  2. Step 2: Effect of changing class attribute

    Changing Dog.species to "Wolf" updates the value for all instances that don't have their own species attribute.
  3. Final Answer:

    Wolf\nWolf -> Option C
  4. Quick Check:

    Changing class attribute affects all instances [OK]
Hint: Changing class attribute changes it for all instances without override [OK]
Common Mistakes:
  • Thinking instances keep old class attribute values
  • Confusing instance and class attributes
  • Expecting different outputs for dog1 and dog2
4. Find the error in this code snippet:
class Book:
    pages = 100

    def __init__(self, pages):
        pages = pages

b = Book(200)
print(b.pages)
medium
A. The instance attribute pages is not set properly
B. The class attribute pages is overwritten incorrectly
C. Syntax error in __init__ method
D. Cannot print pages attribute directly

Solution

  1. Step 1: Analyze __init__ method

    The line pages = pages assigns the parameter to itself, not to the instance.
  2. Step 2: Understand instance attribute setting

    To set an instance attribute, it should be self.pages = pages. Without self., the instance attribute is not created.
  3. Final Answer:

    The instance attribute pages is not set properly -> Option A
  4. Quick Check:

    Use self.pages to set instance attribute [OK]
Hint: Use self.attribute to set instance attributes inside __init__ [OK]
Common Mistakes:
  • Forgetting self. when assigning instance attributes
  • Assuming parameter assignment sets instance attribute
  • Confusing class and instance attributes
5. You want to keep track of how many objects of class Student are created using a class attribute count. Which code correctly updates count each time a new Student is made?
hard
A. class Student: count = 0 def __init__(self): self.count += 1
B. class Student: count = 0 def __init__(self): Student.count += 1
C. class Student: def __init__(self): count = 0 count += 1
D. class Student: count = 0 def __init__(self): count += 1

Solution

  1. Step 1: Identify class attribute usage

    count is a class attribute, so it should be accessed via the class name inside methods.
  2. Step 2: Check each option for correct increment

    class Student: count = 0 def __init__(self): Student.count += 1 uses Student.count += 1, correctly updating the class attribute. class Student: count = 0 def __init__(self): self.count += 1 tries to increment self.count, which creates an instance attribute instead. Options C and D have syntax or scope errors.
  3. Final Answer:

    class Student: count = 0 def __init__(self): Student.count += 1 -> Option B
  4. Quick Check:

    Update class attribute via ClassName.attribute [OK]
Hint: Use ClassName.attribute to update class attributes inside methods [OK]
Common Mistakes:
  • Using self.attribute to update class attribute
  • Defining count inside __init__ instead of class
  • Forgetting to use class name to access class attribute