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

Reckoner reckoner at gmail.com
Wed Jan 28 14:06:21 EST 2009


On Jan 27, 9:46 pm, Steven D'Aprano
<ste... at REMOVE.THIS.cybersource.com.au> wrote:
> On Tue, 27 Jan 2009 13:16:36 -0800, Reckoner 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'.
>
> Can't be done if A is a built-in list, probably can't be done entirely
> generically, but you can probably do it in a cooperative manner.
>
> class TaintList(list):
>     tainted = False
>     def taint(self):
>         self.tainted = True
>     def untaint(self):
>         self.tainted = False
>
> A = TaintList()
>
> import functools
> def taint(parent):
>     def decorator(func):
>         @functools.wraps(func)
>         def f(*args, **kwargs):
>             parent.taint()
>             return func(*args, **kwargs)
>         return f
>     return decorator
>
> class TaintAwareThing(object):
>     def __init__(self):
>         self.attr = 0
>     @taint(A)
>     def change_attribute(self, x):
>         self.attr = x
>
> >>> x = TaintAwareThing()
> >>> y = TaintAwareThing()
> >>> z = TaintAwareThing()
>
> >>> A.extend([x, y, z])
> >>> A.tainted
> False
> >>> x.change_attribute(5)
> >>> A.tainted
>
> True
>
> Here is a second approach: create a proxy class TaintThing that wraps
> whatever object you want, using delegation:
>
> class TaintThing(object):
>     parent = A
>     def __init__(self, obj):
>         self.__dict__['_proxy'] = obj
>     def __getattr__(self, attr):
>         return getattr(self._proxy, attr)
>     def __setattr__(self, attr, value):
>         setattr(self._proxy, attr, value)
>         self.parent.taint()
>
> Now change TaintList to automatically wrap anything stored in it:
>
> # untested
> class TaintList(list):
>     def append(self, obj):
>         list.append(self, TaintThing(obj))
>     # similar for __setitem__, extend, insert
>
> --
> Steven

thanks for your reply.

For the second case where

> class TaintThing(object):
>     parent = A
>     def __init__(self, obj):
>         self.__dict__['_proxy'] = obj
>     def __getattr__(self, attr):
>         return getattr(self._proxy, attr)
>     def __setattr__(self, attr, value):
>         setattr(self._proxy, attr, value)
>         self.parent.taint()

you have told it that parent is 'A'. Shouldn't that be passed to it
somehow in the following:

> # untested
> class TaintList(list):
>     def append(self, obj):
>         list.append(self, TaintThing(obj))
>     # similar for __setitem__, extend, insert

I apologize.  I am probably missing something.  This is getting pretty
advanced for me.

Thanks again.



More information about the Python-list mailing list