Augmented assignment again

Rpoeland Rengelink r.b.rigilink at cable.a2000.nl
Wed Aug 30 02:28:58 EDT 2000


Hi,

Since I expect the following to be(come) a common problem with the
introduction of augmented assignment in Python, I thought I'd put this
up for review

I've been working recently on wrapping an image manipulation library
that only provides in-place arithmetic operators. I've tried
to overload the normal arithmetic operators in terms of
copies and augmented assignment operators with somewhat mixed results.

The simplest implementation is of course:

class Obj:
    ...

    def __add__(self, other):
        result = self.copy()
        return result+=other

Unfortunatly, that means:

>>> a = Obj(data1)
>>> b = Obj(data2)
>>> c = Obj(data3)
>>> d = a+b+c

is equivalent to

>>> tmp = a.copy()
>>> tmp+=b
>>> tmp = tmp.copy()
>>> tmp+=c
>>> d = tmp

(maybe I should've stopped here and just warn my users)
while we would like this to be equivalent to.

>>> tmp = a.copy()
>>> tmp += b
>>> tmp += c
>>> d = tmp

Note that the whole reason that the library only supplies in-place
operations is because copies are horrendously expensive.  My first
attempt to solve this:

class Obj:
    def __init__(self, data):
        ...
        self.is_temporary = 0

    def __add__(self, other):
        if self.is_temporary:
            return self+=other
        else:
            result = self.copy() // expensive
            result.is_temporary = 1
            return result+=other

The above implementation works nicely in the sense that

>>> d = a+b+c

only results in one copy() operation. (a is copied, and b and c are
subsequently added in-place). The problem is that d.is_temporary is
now 1. Hence, subsequent expressions will behave unexpectedly.

>>> e = (d-a)/(d-b)   # e = d == '1'!!

Hence, this implementation is wrong.
I've solved this with the following hack

    def __add__(self):
        if self.is_temporary and self.is_named():
            self.is_temporary = 0
        if self.is_temporary:
            return self+=other
        else:
            result = self.copy() // expensive
            result.is_temporary = 1
            return result+=other
 
    def is_named(self):
        try:
            raise "GetTraceback"
        except "GetTraceback":
            frame = sys.exc_info()[2].tb_frame
            while frame:
                for key, val in frame.f_locals.items():
                    if self == val and key != 'self':
                        return 1
                frame = frame.f_back
        return 0
 
That is: before any aritmhetic operation on a temporary object, check to
see if that object has been named and change the is_temporary to 0 if
this is the case.
 
This seems to work, but I find it ugly (and I'm not entirely sure it
is correct).
 
What I would really like is something like:
 
class Obj:
    ...
 
    def __assign__(self):
        self.is_temporary = 0 

I.e., a function that's invoked whenever an instance is named

Any thoughts/comments?

Cheers,

Roeland



More information about the Python-list mailing list