On Mon, Jun 10, 2013 at 7:57 AM, Rui Maciel <rui.mac...@gmail.com> wrote: > # Case A: this works > model.points[0].position = [2,3,4] > line.points > > # Case B: this doesn't work > test.model.points[0] = test.Point(5,4,7) > line.points > </code> > > > Is there a Python way of getting the same effect with Case B?
It's informative to think about what object is actually being mutated in each of those examples. In A, you are mutating the Point instance by replacing its "position" attribute with a new list. Since the Line object references the same Point instance, it "sees" the change. In B, you are actually mutating a list *containing* the Point instance, by replacing the Point in the list with some new Point. The replaced Point itself is not changed at all (apart from having one fewer reference), and so from the perspective of the Line nothing has changed. There are a couple of ways you might get this to work the way you want. One is by adding as an extra layer a proxy object, which could be as simple as: class Proxy(object): def __init__(self, ref): self.ref = ref Instead of adding points to the model, add instances of Proxy that contain the points. When adding points to the lines, add the same Proxy objects instead. Later, when you want to replace a point in the model, leave the Proxy in place but change the Point it contains by modifying the "ref" attribute. Since the Line only directly references the Proxy, it must follow the same ref attribute to access the Point, and so in that way it will "see" the change. The downsides to this approach are that you have to then use the Proxy objects all over the place and explicitly "dereference" them by using the ref attribute all over the place. Another possibility is to subclass the list used to store the points, in order to modify the way that it replaces items. That could look something like this: class UpdateList(list): def __setitem__(self, index, item): if isinstance(index, slice): indices = range(* index.indices(len(self))) items = list(item) if len(indices) != len(items): raise TypeError("Slice length does not match sequence length") for i, x in zip(indices, items): self[i].update(x) else: self[index].update(item) Then you just need to add an "update" method to the Point class (and any other class you might want to use this with) that would update the Point's attributes to match those of another point. The downside here is that this is not very Pythonic, in that somebody familiar with Python who is reading the code would be surprised by the way the model updates work. A third possibility of course would be to just not try to do case B. Cheers, Ian -- http://mail.python.org/mailman/listinfo/python-list