self-aware list of objects able to sense constituent member alterations?

Reckoner reckoner at gmail.com
Fri Jan 30 13:51:42 CET 2009


On Jan 28, 9:49 am, koranthala <koranth... at gmail.com> wrote:
> On Jan 28, 10:39 pm,Reckoner<recko... at gmail.com> wrote:
>
>
>
> > On Jan 28, 9:16 am, koranthala <koranth... at gmail.com> wrote:
>
> > > On Jan 28, 5:42 pm, koranthala <koranth... at gmail.com> wrote:
>
> > > > On Jan 28, 2:16 am,Reckoner<recko... at gmail.com> wrote:
>
> > > > > I'm not sure this is possible, but I would like to have
> > > > > a list of  objects
>
> > > > > A=[a,b,c,d,...,z]
>
> > > > > where,  in the midst of a lot of processing I might do something like,
>
> > > > > A[0].do_something_which_changes_the_properties()
>
> > > > > which alter the properties of the object 'a'.
>
> > > > > The trick is that I would like A to be mysteriously aware that
> > > > > something about the  object 'a' has changed so that when I revisit A,
> > > > > I will know that the other items in the list need to be refreshed to
> > > > > reflect the changes in A as a result of changing 'a'.
>
> > > > > Even better would be to automatically percolate the subsequent changes
> > > > > that resulted from altering 'a' for the rest of the items in the list.
> > > > > Naturally, all of these items are related in some parent-child
> > > > > fashion.
>
> > > > > that might be a lot to ask, however.
>
> > > > > Any advice appreciated.
>
> > > > I think Python Cookbook has a recipe which deals with this.
> > > > - 6.12 Checking an Instance for Any State Change.
>
> > > Were you able to get this? If not, let me know. I will try to type it
> > > in here - (it is a big recipe, so not doing it now)
>
> > Actually, I have the python cookbook, but cannot find the recipe you
> > mention. maybe I have an older version?
>
> > thanks.
>
> Mine is 2nd Edition.

for posterity's sake, here's the recipe in question:

import copy
class ChangeCheckerMixin(object):
    containerItems = {dict: dict.iteritems, list: enumerate}
    immutable = False
    def snapshot(self):
        ''' create a "snapshot" of self's state -- like a shallow
copy, but
            recursing over container types (not over general
instances:
            instances must keep track of their own changes if
needed).  '''
        if self.immutable:
            return
        self._snapshot = self._copy_container(self.__dict__)
    def makeImmutable(self):
        ''' the instance state can't change any more, set .immutable
'''
        self.immutable = True
        try:
            del self._snapshot
        except AttributeError:
            pass
    def _copy_container(self, container):
        ''' semi-shallow copy, recursing on container types only '''
        new_container = copy.copy(container)
        for k, v in self.containerItems[type(new_container)]
(new_container):
            if type(v) in self.containerItems:
                new_container[k] = self._copy_container(v)
            elif hasattr(v, 'snapshot'):
                v.snapshot( )
        return new_container
    def isChanged(self):
        ''' True if self's state is changed since the last snapshot
'''
        if self.immutable:
            return False
        # remove snapshot from self.__dict__, put it back at the end
        snap = self.__dict__.pop('_snapshot', None)
        if snap is None:
            return True
        try:
            return self._checkContainer(self.__dict__, snap)
        finally:
            self._snapshot = snap
    def _checkContainer(self, container, snapshot):
        ''' return True if the container and its snapshot differ '''
        if len(container) != len(snapshot):
            return True
        for k, v in self.containerItems[type(container)](container):
            try:
                ov = snapshot[k]
            except LookupError:
                return True
            if self._checkItem(v, ov):
                return True
        return False
    def _checkItem(self, newitem, olditem):
        ''' compare newitem and olditem.  If they are containers, call
            self._checkContainer recursively.  If they're an instance
with
            an 'isChanged' method, delegate to that method.
Otherwise,
            return True if the items differ. '''
        if type(newitem) != type(olditem):
            return True
        if type(newitem) in self.containerItems:
            return self._checkContainer(newitem, olditem)
        if newitem is olditem:
            method_isChanged = getattr(newitem, 'isChanged', None)
            if method_isChanged is None:
                return False
            return method_isChanged( )
        return newitem != olditem

if __name__ == '__main__':
    class eg(ChangeCheckerMixin):
        def __init__(self, *a, **k):
            self.L = list(*a, **k)
        def __str__(self):
            return 'eg(%s)' % str(self.L)
        def __getattr__(self, a):
            return getattr(self.L, a)
    x = eg('ciao')
    print 'x =', x, 'is changed =', x.isChanged( )
    # emits: x = eg(['c', 'i', 'a', 'o']) is changed = True
    # now, assume x gets saved, then...:
    x.snapshot( )
    print 'x =', x, 'is changed =', x.isChanged( )
    # emits: x = eg(['c', 'i', 'a', 'o']) is changed = False
    # now we change x...:
    x.append('x')
    print 'x =', x, 'is changed =', x.isChanged( )
    # emits: x = eg(['c', 'i', 'a', 'o', 'x']) is changed = True





More information about the Python-list mailing list