self-aware list of objects able to sense constituent memberalterations?

Discussion in 'Python' started by Reckoner, Jan 27, 2009.

  1. Reckoner

    Reckoner Guest

    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.
     
    Reckoner, Jan 27, 2009
    #1
    1. Advertising

  2. Reckoner

    Chris Rebert Guest

    On Tue, Jan 27, 2009 at 1:16 PM, 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'.


    Have you considered:

    A.change_properties_of_item_and_know_about_it(0)

    ?

    Cheers,
    Chris

    --
    Follow the path of the Iguana...
    http://rebertia.com
     
    Chris Rebert, Jan 27, 2009
    #2
    1. Advertising

  3. 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
     
    Steven D'Aprano, Jan 28, 2009
    #3
  4. Reckoner

    Aaron Brady Guest

    On Jan 27, 3:16 pm, 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'.
    >
    > 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?
     
    Aaron Brady, Jan 28, 2009
    #4
  5. Reckoner

    John O'Hagan Guest

    On Tue, 27 Jan 2009, 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'.
    >
    > Even better would be to automatically percolate the subsequent changes
    > that resulted from altering 'a' for the rest of the items in the list.

    [...]

    Interesting question.

    Maybe this is too simple for your purpose (or maybe just wrong!), but could
    you subclass list and give it an "update" method which keeps a dictionary of
    the state of its members and/or calls another method that makes the
    appropriate changes in the other members when a change occurs, something
    like:

    class SelfAwareList(list):

    state_dict = {}

    def update(self):
    for i in self:
    if i.state == 'some_condition':
    self.do_stuff_to_other_members()
    self.state_dict = i.state

    def do_stuff_to_other_members(self):
    print 'doing stuff...'

    ?

    You could manually call update() on the SelfAwareList instance after calling a
    method on a SelfAwareList member, or even build it into the members' methods
    so that it was automatic.

    HTH,

    John
     
    John O'Hagan, Jan 28, 2009
    #5
  6. Reckoner

    koranthala Guest

    On Jan 28, 2:16 am, 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'.
    >
    > 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.
     
    koranthala, Jan 28, 2009
    #6
  7. Reckoner

    koranthala Guest

    On Jan 28, 5:42 pm, koranthala <> wrote:
    > On Jan 28, 2:16 am, 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'.

    >
    > > 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)
     
    koranthala, Jan 28, 2009
    #7
  8. Reckoner

    Paul McGuire Guest

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


    Check out the Enthought Traits package.

    -- Paul
     
    Paul McGuire, Jan 28, 2009
    #8
  9. Reckoner

    Reckoner Guest

    On Jan 28, 9:16 am, koranthala <> wrote:
    > On Jan 28, 5:42 pm, koranthala <> wrote:
    >
    >
    >
    > > On Jan 28, 2:16 am, 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'.

    >
    > > > 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.
     
    Reckoner, Jan 28, 2009
    #9
  10. Reckoner

    koranthala Guest

    On Jan 28, 10:39 pm, Reckoner <> wrote:
    > On Jan 28, 9:16 am, koranthala <> wrote:
    >
    >
    >
    > > On Jan 28, 5:42 pm, koranthala <> wrote:

    >
    > > > On Jan 28, 2:16 am, 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'.

    >
    > > > > 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.
     
    koranthala, Jan 28, 2009
    #10
  11. Reckoner

    Reckoner Guest

    On Jan 27, 9:46 pm, Steven D'Aprano
    <> 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.
     
    Reckoner, Jan 28, 2009
    #11
  12. On Wed, 28 Jan 2009 11:06:21 -0800, Reckoner wrote:

    > 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



    Sure. Just change the initialisation of TaintThing to something like this:

    #untested
    def __init__(self, obj, parent):
    self.__dict__['_proxy'] = obj
    self.parent = parent


    and then TaintList to something like this:

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





    --
    Steven
     
    Steven D'Aprano, Jan 29, 2009
    #12
  13. Reckoner

    Peter Wang Guest

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


    You should really look at Enthought's Traits package. It does exactly
    what you are asking for, and much, much more. See:

    http://code.enthought.com/projects/traits/documentation.php
    http://code.enthought.com/projects/traits/examples.php

    Using Traits, you could do the following:

    from enthought.traits.api import *
    class Child(HasTraits):
    state = Enum("happy", "sad", "bawling")

    class Parent(HasTraits):
    child = Instance(Child)

    @on_trait_change('child.state')
    def handler(self):
    print "new child state:", self.child.state

    bob_jr = Child()
    bob = Parent(child = bob_jr)

    bob_jr.state = "sad"
    # This would result in bob.handler() being called

    (Disclosure: I work at Enthought and have been using Traits heavily
    for the last 4+ years.)

    -Peter
     
    Peter Wang, Jan 29, 2009
    #13
  14. Reckoner

    Reckoner Guest

    On Jan 28, 10:17 pm, Peter Wang <> wrote:
    > On Jan 27, 3:16 pm,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'.

    >
    > > 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.

    >
    > You should really look at Enthought's Traits package.  It does exactly
    > what you are asking for, and much, much more.  See:
    >
    > http://code.enthought.com/projects/...de.enthought.com/projects/traits/examples.php
    >
    > Using Traits, you could do the following:
    >
    > from enthought.traits.api import *
    > class Child(HasTraits):
    >     state = Enum("happy", "sad", "bawling")
    >
    > class Parent(HasTraits):
    >     child = Instance(Child)
    >
    >     @on_trait_change('child.state')
    >     def handler(self):
    >         print "new child state:", self.child.state
    >
    > bob_jr = Child()
    > bob = Parent(child = bob_jr)
    >
    > bob_jr.state = "sad"
    > # This would result in bob.handler() being called
    >
    > (Disclosure: I work at Enthought and have been using Traits heavily
    > for the last 4+ years.)
    >
    > -Peter


    I haven't looked at Enthought in awhile. I want to avoid having to
    installing the entire Enthought toolsuite, however. Would I have to
    do that for Traits?

    Thanks again.
     
    Reckoner, Jan 30, 2009
    #14
  15. Reckoner

    Reckoner Guest

    On Jan 28, 9:49 am, koranthala <> wrote:
    > On Jan 28, 10:39 pm,Reckoner<> wrote:
    >
    >
    >
    > > On Jan 28, 9:16 am, koranthala <> wrote:

    >
    > > > On Jan 28, 5:42 pm, koranthala <> wrote:

    >
    > > > > On Jan 28, 2:16 am,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'.

    >
    > > > > > 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
     
    Reckoner, Jan 30, 2009
    #15
  16. Reckoner

    Robert Kern Guest

    On 2009-01-29 18:22, Reckoner wrote:

    > I haven't looked at Enthought in awhile. I want to avoid having to
    > installing the entire Enthought toolsuite, however. Would I have to
    > do that for Traits?


    No, Traits can be installed by itself unless if you want its GUI capabilities.

    http://pypi.python.org/pypi/Traits

    --
    Robert Kern

    "I have come to believe that the whole world is an enigma, a harmless enigma
    that is made terrible by our own mad attempt to interpret it as though it had
    an underlying truth."
    -- Umberto Eco
     
    Robert Kern, Jan 30, 2009
    #16
  17. Reckoner

    Guest

    On Jan 28, 4:37 am, John O'Hagan <> wrote:
    > On Tue, 27 Jan 2009, 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'.

    >
    > > Even better would be to automatically percolate the subsequent changes
    > > that resulted from altering 'a' for the rest of the items in the list.

    >
    > [...]
    >
    > Interesting question.
    >
    > Maybe this is too simple for your purpose (or maybe just wrong!), but could
    > you subclass list and give it an "update" method which keeps a dictionary of
    > the state of its members and/or calls another method that makes the
    > appropriate changes in the other members when a change occurs, something
    > like:
    >
    > class SelfAwareList(list):
    >
    >     state_dict = {}
    >
    >     def update(self):
    >         for i in self:
    >             if i.state == 'some_condition':
    >                 self.do_stuff_to_other_members()
    >             self.state_dict = i.state
    >
    >     def do_stuff_to_other_members(self):
    >         print 'doing stuff...'
    >
    > ?
    >
    > You could manually call update() on the SelfAwareList instance after calling a
    > method on a SelfAwareList member, or even build it into the members' methods
    > so that it was automatic.
    >
    > HTH,
    >
    > John


    Hi Reckoner & John O'Hagan,

    Great thread, very interesting.

    John, I haven't seen anything like your class that uses list instead
    of object and refers to state directly (i.state in self). Could you
    elaborate? Here would be my implementation of your idea:

    class SelfAwareList2(object):

    def __init__(self, l):
    self.l = l
    self.changed = [False for element in l]

    def __str__(self):
    return str(self.l)

    def update(self, index, value):
    self.l[index] = value
    self.changed[index] = True

    def do_stuff_to_other_members(self):
    for i in self.changed:
    if i==False:
    self.l += 1

    Here you can print and whenever you update your list, self.changed
    keeps track of what changed. Later on you can call do_stuff_to_others
    which in this case adds 1 to each other element.

    I assume that your class replaces the awkwardness of l.update(0, 5)
    with l[0] = 5, but I can't quite wrap my mind around it.

    Luther.
     
    , Feb 6, 2009
    #17
  18. Reckoner

    John O'Hagan Guest

    On Fri, 6 Feb 2009, wrote:
    > On Jan 28, 4:37 am, John O'Hagan <> wrote:
    > > On Tue, 27 Jan 2009, 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'.
    > > >
    > > > Even better would be to automatically percolate the subsequent changes
    > > > that resulted from altering 'a' for the rest of the items in the list.

    > >
    > > [...]
    > >
    > > Interesting question.
    > >
    > > Maybe this is too simple for your purpose (or maybe just wrong!), but
    > > could you subclass list and give it an "update" method which keeps a
    > > dictionary of the state of its members and/or calls another method that
    > > makes the appropriate changes in the other members when a change occurs,
    > > something like:
    > >
    > > class SelfAwareList(list):
    > >
    > >     state_dict = {}
    > >
    > >     def update(self):
    > >         for i in self:
    > >             if i.state == 'some_condition':
    > >                 self.do_stuff_to_other_members()
    > >             self.state_dict = i.state
    > >
    > >     def do_stuff_to_other_members(self):
    > >         print 'doing stuff...'
    > >
    > > ?
    > >
    > > You could manually call update() on the SelfAwareList instance after
    > > calling a method on a SelfAwareList member, or even build it into the
    > > members' methods so that it was automatic.
    > >
    > > HTH,
    > >
    > > John

    >
    > Hi Reckoner & John O'Hagan,
    >
    > Great thread, very interesting.
    >
    > John, I haven't seen anything like your class that uses list instead
    > of object and refers to state directly (i.state in self). Could you
    > elaborate? Here would be my implementation of your idea:
    >
    > class SelfAwareList2(object):
    >
    > def __init__(self, l):
    > self.l = l
    > self.changed = [False for element in l]
    >
    > def __str__(self):
    > return str(self.l)
    >
    > def update(self, index, value):
    > self.l[index] = value
    > self.changed[index] = True
    >
    > def do_stuff_to_other_members(self):
    > for i in self.changed:
    > if i==False:
    > self.l += 1
    >
    > Here you can print and whenever you update your list, self.changed
    > keeps track of what changed. Later on you can call do_stuff_to_others
    > which in this case adds 1 to each other element.
    >
    > I assume that your class replaces the awkwardness of l.update(0, 5)
    > with l[0] = 5, but I can't quite wrap my mind around it.


    I think my suggestion was much more simplistic than what the OP was after,
    which was far more thoroughly answered by others.

    But as far as my version goes, your implementation is fine as far as I can
    tell; although I (possibly mistakenly) interpreted the OP as wanting
    something which kept track of _how_ the items in the list changed, not just
    _if_ they changed.

    Trying to put together an example was (naturally) more complicated than I
    thought, but here's a silly one, with apologies to Steven D'Aprano among
    others for stealing the parrot theme:

    class Parrot(object):

    def __init__(self, name):
    self.color = 'red'
    self.name = name
    def __repr__(self):
    return self.name

    class SelfAwareListOfParrots(list):

    colors = ['red', 'blue', 'yellow', 'green', 'black', 'white']
    state_dict = {}

    def update(self, changed=None):
    """Ensure no duplicate colors and record changes"""
    for parrot in self:
    used_colors = [parrot.color for parrot in self]
    available_colors = [color for color in self.colors
    if color not in used_colors]
    if (parrot is not changed and
    used_colors.count(parrot.color) > 1):
    parrot.color = available_colors[0]
    self.state_dict[parrot] = parrot.color

    def change(self, parrot, color):
    """Change color and update"""
    self[self.index(parrot)].color = color
    self.update(parrot)

    This list knows when a parrot has had its color changed by calling change() on
    the list, and makes sure no parrots are the same color by changing any
    parrots of duplicate color. It has a state_dict attribute (redundant in this
    example) which keeps track of the colors after an update. (My version of the
    update method updates the whole list).

    The trick is to have the method that changes the elements of the list defined
    in the list class definition, rather than that of the elements' class, that
    way it's easy for the list to know about changes to its elements.

    (If a parrots color is changed directly, update() will still ensure unique
    colors, but will not preserve the change unless that parrot is given as an
    argument.)

    For example:

    polly = Parrot('polly')
    molly = Parrot('molly')
    dolly = Parrot('dolly')

    salp = SelfAwareListOfParrots([polly, molly, dolly])

    print salp.state_dict

    >>>{molly: 'yellow', polly: 'white', dolly: 'black'}


    salp.change(polly, 'black')

    print salp.state_dict

    >>>{molly: 'yellow', polly: 'black', dolly: 'white'}


    As for the subclassing of list, that allows you to create a class with all the
    methods of a list, to which you can add your own. (Although any list methods
    which return a new list will return a list, not an instance of your class,
    unless you define them to do so in your class definition).

    In my post quoted above, by "i.state" I was probably abusing the term "state"
    to signify "some arbitrary attribute" of i.

    I'm pretty new to this stuff, but there are plenty of tutorials on it out
    there, and I'm relying on others to correct any fallacies I may be
    unwittingly propagating here. :)

    Regards,

    John
     
    John O'Hagan, Feb 9, 2009
    #18
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ralf W. Grosse-Kunstleve
    Replies:
    16
    Views:
    586
    Lonnie Princehouse
    Jul 11, 2005
  2. Ralf W. Grosse-Kunstleve
    Replies:
    18
    Views:
    599
    Bengt Richter
    Jul 11, 2005
  3. Ralf W. Grosse-Kunstleve
    Replies:
    2
    Views:
    404
    Dan Sommers
    Jul 12, 2005
  4. falcon
    Replies:
    0
    Views:
    379
    falcon
    Jul 31, 2005
  5. Bart Kastermans
    Replies:
    6
    Views:
    407
    Bart Kastermans
    Jul 13, 2008
Loading...

Share This Page