Skip to content

How to fix: Python class instance not re-instantiated?

In Python, the issue of a class instance “not re-instantiating” typically refers to a logic error where subsequent calls to a class constructor appear to return an object that retains the state of a previous instance. This is rarely a failure of the Python interpreter to allocate new memory; rather, it is usually a symptom of shared state via class-level attributes or mutable default arguments in the __init__ method.

To an engineer, this manifests as a “leaky” state where instance_b.data contains values added to instance_a.data, even though instance_b was just created.

Cause Description Technical Impact
Mutable Default Arguments Using list, dict, or set as a default parameter in __init__. The default object is created once at definition time and shared across all instances.
Class-level Attributes Defining variables outside the __init__ method. Attributes are bound to the __class__ object, not the self instance.
Singleton Pattern / __new__ Overriding the __new__ method incorrectly. The logic explicitly returns an existing reference instead of a new allocation.
Module Caching Re-importing a module thinking it resets global instances. importlib.reload() is required; standard imports are cached in sys.modules.

If your constructor looks like def __init__(self, items=[]), every instance shares the same list. Use None as a sentinel value instead.

# ❌ INCORRECT: Shared list across all instances
class DataStack:
def __init__(self, items=[]):
self.items = items
# ✅ CORRECT: Unique list for every instance
class DataStack:
def __init__(self, items=None):
if items is None:
self.items = []
else:
self.items = items

Variables defined directly under the class keyword are static/class variables. To ensure re-instantiation resets values, move them into self.

# ❌ INCORRECT: Persistent class state
class Tracker:
count = 0 # Shared by all instances
data = {} # Shared by all instances
# ✅ CORRECT: Instance-specific state
class Tracker:
def __init__(self):
self.count = 0
self.data = {}

To verify if you are actually getting a new instance, compare the memory addresses using the id() function or the is operator.

obj1 = MyClass()
obj2 = MyClass()
print(f"Object 1 ID: {id(obj1)}")
print(f"Object 2 ID: {id(obj2)}")
if obj1 is obj2:
print("CRITICAL: Both variables point to the same memory address.")

If you are inheriting from a library or implementing a Singleton, check the __new__ method. __new__ handles the actual creation of the instance, while __init__ merely initializes it.

class DatabaseConnection:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance # This prevents "re-instantiation"
  1. Use Type Hinting and Linting: Use tools like mypy or flake8 with the flake8-bugbear plugin. It will automatically flag B006 (Do not use mutable default arguments).
  2. Explicit Initialization: Always initialize your instance variables within the __init__ method to ensure they are bound to self.
  3. Immutable Defaults: If you need a default value, use an immutable type (e.g., tuple instead of list) if possible.
  4. Factory Methods: For complex instantiation, use @classmethod factory methods to ensure clean state generation.
  5. Clean Up: If using a Singleton pattern intentionally, provide a clear_instance() or teardown() method for unit testing purposes to allow fresh instantiation between tests.