[ZODB-Dev] PersistentList Python 2.2-style implementation
Mike C. Fletcher
mcfletch@geocities.com
Tue, 12 Feb 2002 22:45:24 -0500
This is a multi-part message in MIME format.
--------------040004000206050802060503
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit
Well, got the Zope-3x-branch stuff working locally (for the longest time
I didn't realise I needed to use a branch checkout). First thing I
discovered I needed was a new PersistentList class (the old one was
complaining about not getting initialised (it assumed the underlying
list was in self.data)).
So, attached is my first crack at an implementation. Nothing
particularly special, just an auto-generated set of method wrappers.
Unfortunately, this implementation (like the previous one) still doesn't
support efficient large collections of objects. For instance, if you
put 10,000 objects in the list, it will load all 10,000 objects whenever
you touch the list.
I can see a way of creating a more elaborate class, where the list just
stores the oids, and a mapping handles actual storage of the objects so
that doing list[x:y] would get the oids for elements x through y, then
retrieve only those elements from the mapping. It gets kinda messy when
you want to delete items (lots of "if oid not in list" stuff), but not
horribly so. For my current project, not necessary, so I won't do it
just now, but it might be useful as a utility class someday.
Enjoy all,
Mike
_______________________________________
Mike C. Fletcher
http://members.rogers.com/mcfletch/
--------------040004000206050802060503
Content-Type: text/plain;
name="PersistentList.py"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="PersistentList.py"
"""Persistent List classes for ZODB3 (and ZODB2)
The new persistent list class provides a sub-class of
list which sets the _p_changed attribute of the object
when list-modifying methods are called on the list
"""
from Persistence import Persistent
class PersistentList( list, Persistent ):
"""ZODB3 Persistent List class using Python 2.2 object inheritence
This sub-class uses the Persistence machinery in Persistence.Persistent
to store a list of object references. The current implementation does
nothing to make the storage intelligent/efficient (it just stores the
whole list on save and restores it on load). An implementation with a
level of indirection allowing for not loading all items would likely
be preferable when large numbers of (particularly) non-Persistent-derived
objects are stored in the list.
"""
# don't see where this is set in Persistent if no attribute
# accesses have occured, might be a bug in Persistent?
_p_atime = 0
def __delitem__( self, *arguments, **namedarguments ):
'x.__delitem__(y) <==> del x[y]'
value = list.__delitem__( self, *arguments, **namedarguments )
self._p_set_changed( 1 )
return value
def __delslice__( self, *arguments, **namedarguments ):
'x.__delslice__(i, j) <==> del x[i:j]'
value = list.__delslice__( self, *arguments, **namedarguments )
self._p_set_changed( 1 )
return value
def __iadd__( self, *arguments, **namedarguments ):
'x.__iadd__(y) <==> x+=y'
value = list.__iadd__( self, *arguments, **namedarguments )
self._p_set_changed( 1 )
return value
def __imul__( self, *arguments, **namedarguments ):
'x.__imul__(y) <==> x*=y'
value = list.__imul__( self, *arguments, **namedarguments )
self._p_set_changed( 1 )
return value
def __setitem__( self, *arguments, **namedarguments ):
'x.__setitem__(i, y) <==> x[i]=y'
value = list.__setitem__( self, *arguments, **namedarguments )
self._p_set_changed( 1 )
return value
def __setslice__( self, *arguments, **namedarguments ):
'x.__setslice__(i, j, y) <==> x[i:j]=y'
value = list.__setslice__( self, *arguments, **namedarguments )
self._p_set_changed( 1 )
return value
def append( self, *arguments, **namedarguments ):
'L.append(object) -- append object to end'
value = list.append( self, *arguments, **namedarguments )
self._p_set_changed( 1 )
return value
def extend( self, *arguments, **namedarguments ):
'L.extend(list) -- extend list by appending list elements'
value = list.extend( self, *arguments, **namedarguments )
self._p_set_changed( 1 )
return value
def insert( self, *arguments, **namedarguments ):
'L.insert(index, object) -- insert object before index'
value = list.insert( self, *arguments, **namedarguments )
self._p_set_changed( 1 )
return value
def pop( self, *arguments, **namedarguments ):
'L.pop([index]) -> item -- remove and return item at index (default last)'
value = list.pop( self, *arguments, **namedarguments )
self._p_set_changed( 1 )
return value
def remove( self, *arguments, **namedarguments ):
'L.remove(value) -- remove first occurrence of value'
value = list.remove( self, *arguments, **namedarguments )
self._p_set_changed( 1 )
return value
def reverse( self, *arguments, **namedarguments ):
'L.reverse() -- reverse *IN PLACE*'
value = list.reverse( self, *arguments, **namedarguments )
self._p_set_changed( 1 )
return value
def sort( self, *arguments, **namedarguments ):
'L.sort([cmpfunc]) -- sort *IN PLACE*; if given, cmpfunc(x, y) -> -1, 0, 1'
value = list.sort( self, *arguments, **namedarguments )
self._p_set_changed( 1 )
return value
if __name__ == '__main__':
def generate():
# this stuff just auto-generates the class contents from a template
# considerably more convenient than typing it out
template = """ def %(name)s( self, *arguments, **namedarguments ):
%(doc)s
value = list.%(name)s( self, *arguments, **namedarguments )
self._p_set_changed( 1 )
return value
"""
for name in [
'__delitem__',
'__delslice__',
'__iadd__',
'__imul__',
'__setitem__',
'__setslice__',
'append',
'extend',
'insert',
'pop',
'remove',
'reverse',
'sort'
]:
doc = repr(getattr([],name).__doc__)
print template% globals()
generate()
--------------040004000206050802060503--