API Reference
memo (decorator)

The @dbzero.memo decorator is the core of dbzero, transforming a standard Python class into a persistent, memory-managed data model. It transparently handles the serialization, storage, and lifecycle of your objects, allowing you to interact with them as if they were regular in-memory instances.


Signature

@db0.memo(singleton: bool = False, prefix: str | None = None, no_default_tags: bool = False)

The decorator is applied directly to a class definition. All arguments are optional.


Parameters

  • singleton (bool): When True, the decorated class becomes a singleton within its prefix. The first time you instantiate the class, the object is created and persisted. All subsequent calls to the constructor within the same prefix will return this exact same instance, ignoring any new arguments. Defaults to False.
  • prefix (str): Specifies a static namespace for the class and all its instances. This is useful for organizing data. If not provided, the class uses the current active prefix set by dbzero.open().
  • no_default_tags (bool): If True, dbzero will not automatically add default system tags (such as the class name) to new instances of this class. Defaults to False.

Behavior and Side Effects

The @dbzero.memo decorator fundamentally alters the behavior of a class to integrate it with the dbzero persistence engine.

Object Persistence

Instances of a memoized class are automatically persisted. Any changes to their attributes are tracked and saved to the memory-mapped file, either on dbzero.commit() or through autocommit mechanisms.

@db0.memo
class Task:
    def __init__(self, description):
        self.description = description
        self.completed = False
 
# Creates a new persistent object
task1 = Task("Write documentation")
 
# Attribute modifications are automatically persisted
task1.completed = True

Automatic Garbage Collection

dbzero uses reference counting to manage the object lifecycle. When a memoized object is stored as an attribute of another, dbzero tracks this relationship. If the parent object is deleted or the attribute is reassigned, the child object is automatically deleted if no other persistent objects reference it.

💡

Automatic Cleanup: You don't need to manually delete child objects. dbzero handles the cascading deletion of unreferenced dependencies, preventing orphaned data.

@db0.memo
class User:
    def __init__(self, name, profile):
        self.name = name
        self.profile = profile # User references a Profile object
 
@db0.memo
class Profile:
    def __init__(self, bio):
        self.bio = bio
 
# Create a user with a profile
user_profile = Profile("Developer")
user = User("Alex", user_profile)
profile_uuid = db0.uuid(user_profile)
 
# When `user` is deleted, its exclusively-owned `profile` is also deleted.
db0.delete(user)
db0.commit()
 
# Attempting to fetch the now-deleted profile will raise an exception.
# with pytest.raises(Exception):
#   db0.fetch(profile_uuid)

Singleton Pattern

Using singleton=True ensures only one instance of a class exists per prefix, which is ideal for global state or configuration objects.

@db0.memo(singleton=True)
class AppSettings:
    def __init__(self, theme="dark"):
        self.theme = theme
 
# First call creates the object
settings1 = AppSettings(theme="light")
print(settings1.theme) #-> "light"
 
# Subsequent calls return the *same* object; arguments are ignored.
settings2 = AppSettings(theme="dark")
print(settings2.theme) #-> "light"

Special Method Integration

dbzero respects many of Python's special "dunder" methods, allowing your persistent objects to behave like native Python objects.

  • __repr__: A custom __repr__ will be used for the object's representation.
  • __eq__, __lt__, etc.: If you implement comparison operators, they will work correctly for comparing instances.
  • __load__: You can define a __load__(self) method to provide a custom dictionary representation of your object for persistence. This gives you fine-grained control over the stored data structure.
@db0.memo
class Record:
    def __init__(self, id_val, data):
        self.id_val = id_val
        self.data = data
 
    # Define a custom representation for the object
    def __repr__(self):
        return f"<Record id={self.id_val}>"
 
    # Define how instances are compared
    def __eq__(self, other):
        if isinstance(other, Record):
            return self.id_val == other.id_val
        return NotImplemented
 
record1 = Record(1, "abc")
record2 = Record(1, "xyz")
 
print(record1)      #-> <Record id=1>
print(record1 == record2) #-> True