Skip to content

How to Count the Number of Instances of a Class in Python

Learn how to track Python class instances with class variables, __init__/__del__ methods, and weakref for accurate counting in resource pools, debugging, or connection limits.

Tracking how many objects have been created from a class is a common requirement in Python, whether you're managing resource pools, implementing the observer pattern, debugging memory usage, monitoring application state, or enforcing instance limits.

In this guide, you'll learn multiple methods to count class instances in Python, from simple class variables to more robust approaches that handle instance deletion.

Using a Class Variable as a Counter

The most straightforward approach is to use a class variable that increments every time the constructor (__init__) is called:

class User:
    instance_count = 0

    def __init__(self, name):
        self.name = name
        User.instance_count += 1

user1 = User("Alice")
user2 = User("Bob")
user3 = User("Charlie")

print(f"Total User instances: {User.instance_count}")

Output:

Total User instances: 3

How it works:

  1. instance_count is a class variable shared by all instances. It belongs to the class itself, not to any individual object.
  2. Each time __init__ is called (i.e., a new object is created), the counter increments.
  3. Access it via User.instance_count (on the class) or user1.instance_count (on any instance).

Tracking Instance Deletion with __del__

The basic counter only increments. It doesn't decrease when objects are deleted. To accurately track live instances, decrement the counter in the destructor:

class Connection:
    active_count = 0

    def __init__(self, host):
        self.host = host
        Connection.active_count += 1
        print(f"Connected to {host} (active: {Connection.active_count})")

    def __del__(self):
        Connection.active_count -= 1
        print(f"Disconnected from {self.host} (active: {Connection.active_count})")


conn1 = Connection("server-1")
conn2 = Connection("server-2")
conn3 = Connection("server-3")

print(f"\nActive connections: {Connection.active_count}")

del conn2

print(f"Active connections: {Connection.active_count}")

Output:

Connected to server-1 (active: 1)
Connected to server-2 (active: 2)
Connected to server-3 (active: 3)

Active connections: 3
Disconnected from server-2 (active: 2)
Active connections: 2
Disconnected from server-1 (active: 1)
Disconnected from server-3 (active: 0)

Tracking Both Total and Active Instances

For comprehensive monitoring, track both the total number of instances ever created and the current number of live instances:

class Task:
    total_created = 0
    active_count = 0

    def __init__(self, name):
        self.name = name
        Task.total_created += 1
        Task.active_count += 1

    def __del__(self):
        Task.active_count -= 1

    @classmethod
    def stats(cls):
        print(f"Total created: {cls.total_created}")
        print(f"Currently active: {cls.active_count}")
        print(f"Deleted: {cls.total_created - cls.active_count}")


t1 = Task("Build")
t2 = Task("Test")
t3 = Task("Deploy")

del t2

Task.stats()

Output:

Total created: 3
Currently active: 2
Deleted: 1

Using a Set to Track All Live Instances

If you need access to the actual instances (not just the count), store weak references to avoid preventing garbage collection:

import weakref

class Sensor:
    _instances = set()

    def __init__(self, sensor_id):
        self.sensor_id = sensor_id
        Sensor._instances.add(weakref.ref(self, Sensor._remove_ref))

    @classmethod
    def _remove_ref(cls, ref):
        cls._instances.discard(ref)

    @classmethod
    def count(cls):
        return len(cls._instances)

    @classmethod
    def all_instances(cls):
        return [ref() for ref in cls._instances if ref() is not None]


s1 = Sensor("temp-01")
s2 = Sensor("humidity-02")
s3 = Sensor("pressure-03")

print(f"Active sensors: {Sensor.count()}")
print(f"Sensor IDs: {[s.sensor_id for s in Sensor.all_instances()]}")

del s2

print(f"After deletion: {Sensor.count()}")

Output:

Active sensors: 3
Sensor IDs: ['pressure-03', 'temp-01', 'humidity-02']
After deletion: 2

Counting Instances in Subclasses

When using inheritance, decide whether subclass instances should count toward the parent's total:

class Animal:
    count = 0

    def __init__(self, name):
        self.name = name
        Animal.count += 1


class Dog(Animal):
    dog_count = 0

    def __init__(self, name, breed):
        super().__init__(name)
        Dog.dog_count += 1
        self.breed = breed


class Cat(Animal):
    cat_count = 0

    def __init__(self, name, color):
        super().__init__(name)
        Cat.cat_count += 1
        self.color = color


d1 = Dog("Rex", "Labrador")
d2 = Dog("Max", "Poodle")
c1 = Cat("Whiskers", "Orange")

print(f"Total animals: {Animal.count}")
print(f"Dogs: {Dog.dog_count}")
print(f"Cats: {Cat.cat_count}")

Output:

Total animals: 3
Dogs: 2
Cats: 1

Practical Example: Connection Pool

A real-world use case is limiting the number of active connections:

class DatabaseConnection:
    MAX_CONNECTIONS = 3
    active_count = 0

    def __init__(self, db_name):
        if DatabaseConnection.active_count >= DatabaseConnection.MAX_CONNECTIONS:
            raise RuntimeError(
                f"Connection limit reached ({DatabaseConnection.MAX_CONNECTIONS}). "
                "Close an existing connection first."
            )
        self.db_name = db_name
        DatabaseConnection.active_count += 1
        print(f"Connected to '{db_name}' ({DatabaseConnection.active_count}/{DatabaseConnection.MAX_CONNECTIONS})")

    def close(self):
        DatabaseConnection.active_count -= 1
        print(f"Closed '{self.db_name}' ({DatabaseConnection.active_count}/{DatabaseConnection.MAX_CONNECTIONS})")

    def __del__(self):
        if DatabaseConnection.active_count > 0:
            DatabaseConnection.active_count -= 1


conn1 = DatabaseConnection("users_db")
conn2 = DatabaseConnection("orders_db")
conn3 = DatabaseConnection("analytics_db")

try:
    conn4 = DatabaseConnection("logs_db")
except RuntimeError as e:
    print(f"\nError: {e}")

conn2.close()
conn4 = DatabaseConnection("logs_db")

Output:

Connected to 'users_db' (1/3)
Connected to 'orders_db' (2/3)
Connected to 'analytics_db' (3/3)

Error: Connection limit reached (3). Close an existing connection first.
Closed 'orders_db' (2/3)
Connected to 'logs_db' (3/3)

Quick Comparison of Methods

Method Tracks Live Instances Handles Deletion Access to Instances Complexity
Class variable counter ❌ (total only) ❌ ❌ Simple
Counter + __del__ ✅ ✅ ❌ Moderate
weakref set ✅ ✅ (automatic) ✅ Advanced
Separate counters per subclass ✅ Optional ❌ Moderate

Conclusion

Counting class instances in Python is straightforward using class variables that increment in __init__:

  • Use a simple class counter when you only need the total number of objects ever created.
  • Add a __del__ method to decrement the counter when you need to track currently active instances.
  • Use weakref when you need access to the actual live instances without preventing garbage collection.
  • Use separate counters in parent and child classes when you need to track instances per type in an inheritance hierarchy.

For most applications, a class variable with increment in __init__ and decrement in __del__ provides the right balance of simplicity and accuracy.

Navigation