[ZODB-Dev] Re: false write conflicts

Casey Duncan casey at zope.com
Tue Mar 2 12:39:27 EST 2004


On Tue, 02 Mar 2004 12:10:51 -0500
John Belmonte <john at neggie.net> wrote:

> Casey Duncan wrote:
> > John Belmonte <john at neggie.net> wrote:
> > 
> >>Casey Duncan wrote:
> >>
> >>>Augmented assignment causes a setattr on the containing object.
> >This>>is the way Python works. These examples are semantically
> >>>equivilant::
> >>>
> >>>  self.x += 1
> >>>  self.x = self.x + 1
> >>>  setattr(self, 'x', self.x + 1)
> >>>
> >>>They all cause self to be modified through __setattr__. If self is
> >a>>persistent instance then it will be marked changed in all three
> >>>cases above.
> >>
> >>To be more accurate, it seems like
> >>
> >>    foo.bar += 1
> >>
> >>becomes the equivalent of
> >>
> >>    x = foo.bar; x += 1; foo.bar = x
> > 
> > Ok, I'm not sure how that's more accurate ;^) My example don't
> > create a local variable 'x'.
> 
> The reason I said that was because your equivalents didn't show the +=
> 
> operator being called on the attribute object.  What I'm trying to
> show is that Python doesn't blow off calling the object's += method
> just because it's accessed as an attribute of some other object.
> 
> >>That is arguably a Python wart.  With regard to the containing
> >object,>
> >>it seems unfortunate to consider "foo.bar +=1" different than 
> >>"foo.bar[a] = b".
> > 
> > It's not a wart. Augmented assignment is an assignment operation. If
> > it is an assignent to an attribute, that changes the containing
> > object. A positive side-affect of this wrt persistence is that
> > augmented assigment of mutable non-persistent attributes actually
> > does the "right thing". i.e.::
> > 
> > Where:
> >   self.x = []
> > 
> >   self.x += 'foo'
> > 
> > marks self as changed which actually "helps" you since
> > self.x.append('foo') wouldn't.
> 
> I guess my view is different than Python's, but the augmented
> assignment is an assignment to the object contained in the attribute,
> not to the container (that is, the containing class).  It doesn't
> change the containing object unless the augmented operation yields a
> new object (and my setattr wrapper handles this case fine).

I think that differentiating between mutable and immutable attribute
augmented assignment in this way is even more subtle and mysterious. To
my simple mind, the equal sign mean assignment, and self.x += 1 and
self.x = 1 both assign to self regardless of the nature of x.
 
>  From your example, I consider "self.x += 'foo'" triggering a database
>  
> write, while "self.x.append('foo')" does not, to be inconsistent and 
> useless.  list.__iadd__ and list.append have the same meaning.

The fact the self.x.append('foo') does not is a ZODB wart, yes. ZODB
tries to be wholly transparent, but cannot account for mutable objects
in the database that are not persistent. It has no way to detect changes
to non-persistent objects.

One could envision a different approach to persistence (hands wave and
magical stardust appears overhead to percussive indian string music)
where objects in the database were proxied rather than deriving from a
common base class. So long as the proxies were there then we could
monitor changes to objects from above rather than below. This is not
without it's own set of difficulties, limitations and complexities,
however.

Another approach would be to instrument Python so that application code
could monitor mutable objects in some way. Some sort of "dispatch on
change" protocol or something.
 
> >>This wrapper for Persistent.__setattr__ looks like it will suit my
> >>needs:
> >>
> >>   class MyPersistent(Persistent):
> >>     def __setattr__(self, key, val):
> >>       if not (self.__dict__.has_key(key) and self.__dict__[key] is
> >>       val):
> >>         Persistent.__setattr__(self, key, val)
> > 
> > Ugh. This is bound to bite you somewhere down the line. I'd say its
> > simpler to avoid augmented assignment when you don't want the
> > container marked as changed. But that's me.
> 
> I don't think it will bite me because it makes the behavior of 
> persistent objects match the model in my head:  if I don't assign a
> new object or value to an attribute, don't flag the containing object
> as dirty.

Writing setattr hooks properly is a black art. Writing persistent
setattr hooks is more like hearding bees blindfolded...

-Casey



More information about the ZODB-Dev mailing list