Persistent Objects Base Class

6.5 · active · verified Wed Apr 15

The `persistent` library provides a base class, `Persistent`, for creating translucent persistent Python objects. These objects can track their their own 'dirty' state, indicating when they have been modified and need to be saved by an external persistence layer (e.g., ZODB). It is a fundamental component for building object persistence systems. The current version is 6.5, with major releases typically aligning with Python version support updates and addressing core behavior changes.

Warnings

Install

Imports

Quickstart

Demonstrates the basic usage of `persistent.Persistent` by subclassing it and observing how its `_p_changed` attribute is affected by direct attribute assignments. It also highlights a common gotcha regarding changes to mutable attributes within the object when not managed by a full persistence layer.

from persistent import Persistent

class MyPersistentObject(Persistent):
    def __init__(self, name="Default"):
        self.name = name
        self.attributes = {} # A mutable dictionary

    def update_name(self, new_name):
        # Assigning to a direct attribute will mark the object dirty
        self.name = new_name

    def add_attribute(self, key, value):
        # For objects managed by a persistence layer (e.g., ZODB), 
        # modifying this dict would also mark the parent dirty. 
        # Without a persistence layer, direct dict modification here
        # does NOT automatically set _p_changed.
        self.attributes[key] = value

    def describe(self):
        return f"Name: {self.name}, Attributes: {self.attributes}"

# Create an instance
my_obj = MyPersistentObject("Initial Name")
print(f"1. Initial state: {my_obj.describe()}, _p_changed: {my_obj._p_changed}")

# Modifying a direct attribute marks it dirty
my_obj.update_name("New Name 1")
print(f"2. After update_name: {my_obj.describe()}, _p_changed: {my_obj._p_changed}")

# Simulate 'saving' (a persistence layer would set _p_changed to None)
my_obj._p_changed = None
print(f"3. After 'saving': {my_obj.describe()}, _p_changed: {my_obj._p_changed}")

# Modifying the mutable dictionary directly (without a storage proxy)
# does NOT automatically set _p_changed, which is a common gotcha.
my_obj.attributes['version'] = 1
print(f"4. After modifying internal dict: {my_obj.describe()}, _p_changed: {my_obj._p_changed}")

# To ensure persistence layer detects changes in mutable objects,
# you often need to manually set _p_changed or reassign the attribute
# (e.g., obj.attributes = new_dict_or_copy) or rely on a proxy provided by the storage.
my_obj._p_changed = True
print(f"5. Manually set _p_changed after internal change: {my_obj.describe()}, _p_changed: {my_obj._p_changed}")

view raw JSON →