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

Aaron Brady castironpi at gmail.com
Wed Jan 28 10:24:54 CET 2009


On Jan 27, 3:16 pm, 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.

What you could do is specialize '__getitem__' (or '__getslice__') so
that whenever one of its items is accessed, the item is marked as
dirty or the entire list is refreshed.  (Unproduced.)

def taintlist(list):
  def __getitem__( self, key ):
    x= super(taintlist, self).__getitem__( self, key )
    self._dirty= True
    self.refresh()  #too early, unfortunately
    return x
  ...

However, what you are probably after is something like this
(unproduced):

def taintlist(list):
  def __getitem__( self, key ):
    x= super(taintlist, self).__getitem__( self, key )
    y= delegate( self, key, x )
    return y

The 'delegate' class, also unproduced, automatically delegates
function calls (including member lookups) to the target.  After the
delegated call returns, the list is notified-- hence the three
arguments to its constructor.  (Unproduced.)

class delegate:
  def __getattr__( self, key ):
    attr= super( delegate, self ).__getattr__( self, key )
    deleg= delegate( self.owner, self.ownerkey, attr )
    return deleg
  def __call__( self, *ar, **kw ):
    res= self.attr( *ar, **kw )
    self.owner.markdirty( )
    return res

I'm not convinced it's possible, but there's a possibility... or
something like it.  When you call a[0].meth(), three things happen:

x= '0' looked up on 'a'
y= 'meth' looked up on 'x'
z= 'y' called

You want control over the last of these parts, so you can call a
custom function instead.  It becomes increasingly risky as the depth
increases, such as if the target class implements custom access, I
guess.  In the 'delegate' shown, for example, it assumes that the
result is callable.  You might need:

class delegate:
  def __getattr__( self, key ):
    attr= super( delegate, self ).__getattr__( self, key )
    if not iscallable( attr ):
      return attr
    ... #return delegate

Further, if the result is callable, that doesn't mean it will
necessarily be called.  You should be able to tolerate this sequence:

x= '0' looked up on 'a'
y= 'meth' looked up on 'x'
z= attribute looked up on 'y' (instead of 'y' called)

Mind if we inquire after your progress?



More information about the Python-list mailing list