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