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): WhenTrue, 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 toFalse.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 bydbzero.open().no_default_tags(bool): IfTrue,dbzerowill not automatically add default system tags (such as the class name) to new instances of this class. Defaults toFalse.
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 = TrueAutomatic 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