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

Steven D'Aprano steven at REMOVE.THIS.cybersource.com.au
Wed Jan 28 00:46:46 EST 2009


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



More information about the Python-list mailing list