Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement a persistent Python `list`?

Tags:

python

I'm trying to make an object act like a built-in list, except that its value be saved once modified.

The implementation I come up with is wrapping a list in a PersistentList class. For every access to method that may change the list, the wrapper delegates to the wrapped list, and save it to a key-value database after it's invoked.

Code:

class PersistentList(object):
    def __init__(self, key):
        self.key = key 
        self._list = db.get(key, []) 

    def __getattr__(self, name):
        attr = getattr(self._list, name)
        if attr:
            if attr in ('append', 'extend', 'insert', 'pop',
                'remove', 'reverse', 'sort'):
                attr = self._autosave(attr)
            return attr
        raise AttributeError

    def _autosave(self, func):
        @wraps(func)
        def _(*args, **kwargs):
            ret = func(*args, **kwargs)
            self._save()
            return ret 
        return _

    def _save(self):
        db.set(self.key, self._list)

There are several problems with this implementation:

  1. I have to decorate methods like append every time they are accessed, is there a better way to decorate multiple methods of some object?

  2. Operations like l += [1,2,3] don't work because I haven't implemented the iadd method.

What can I do to simplify this?

like image 288
satoru Avatar asked Feb 26 '12 01:02

satoru


1 Answers

I like @andrew cooke's answer but I see no reason why you can't derive directly from a list.

class PersistentList(list):
    def __init__(self, *args, **kwargs):
        for attr in ('append', 'extend', 'insert', 'pop', 'remove', 'reverse', 'sort'):
            setattr(self, attr, self._autosave(getattr(self, attr))
        list.__init__(self, *args, **kwargs)
    def _autosave(self, func):
        @wraps(func)
        def _func(*args, **kwargs):
            ret = func(*args, **kwargs)
            self._save()
            return ret 
        return _func
like image 65
mattbornski Avatar answered Sep 28 '22 07:09

mattbornski