__iadd__ useless in sub-classed int

S

samwyse

For whatever reason, I need an inproved integer. Sounds easy, let's
just subclass int:
pass

Now let's test it:
0

So far, so good. Now let's try incrementing:
<type 'int'>

WTF??!
Is this a bug or is it the inevitable result of optimizing for the
case where all integers are indistinguishable?
 
D

Diez B. Roggisch

samwyse said:
For whatever reason, I need an inproved integer. Sounds easy, let's
just subclass int:

pass

Now let's test it:

0

So far, so good. Now let's try incrementing:

<type 'int'>

WTF??!
Is this a bug or is it the inevitable result of optimizing for the
case where all integers are indistinguishable?

There has been a lengthe thread over the semantics of __iadd__ a few
weeks ago. It _can_ modify the object in question in-place (something
not possible for ints anyway), but it will ALWAYS return a reference
which will be set to the left-hand-side.

zed = zed.__iadd__(1)

So - you need to overload the __iadd__-method to return a test-instance.

Diez
 
S

samwyse

There has been a lengthe thread over the semantics of __iadd__ a few
weeks ago. It _can_ modify the object in question in-place (something
not possible for ints anyway), but it will ALWAYS return a reference
which will be set to the left-hand-side.

Thanks! I'd missed that thread, googling found it but it didn't look
noteworthy at first glance. I've not yet read the entire thread, but
I did see a reference to PEP 203.

) So, given the expression:
)
) x += y
)
) The object `x' is loaded, then `y' is added to it, and the
) resulting object is stored back in the original place.

That agrees with what I'm seeing, all right. The problem is, the
resulting object has a different type, which seems to violate the
spirit of a later paragraph:

) Writing the above expression as
)
) <x> <operator>= <y>
)
) is both more readable and less error prone, because it is
) instantly obvious to the reader that it is <x> that is being
) changed, and not <x> that is being replaced by something almost,
) but not quite, entirely unlike <x>.

And that's my complaint. The value in <zed> is being replaced by
something almost, but not quite, identical to the original value.
Python's internal implementation of __iadd__ for <int> isn't returning
<self>, it's returning a new value belonging to the super-class. My
whole point is overloading <int> was that I'd hoped to avoid having to
write a bunch of methods to perform in-place modifications. Looks
like I stuck, however.
 
N

Neil Cerutti

And that's my complaint. The value in <zed> is being replaced
by something almost, but not quite, identical to the original
value. Python's internal implementation of __iadd__ for <int>
isn't returning <self>, it's returning a new value belonging to
the super-class.

int.__iadd__ cannot return self because int instances are
immutable. In order to return self it would first have to change
what's unchangeable.
My whole point is overloading <int> was that
I'd hoped to avoid having to write a bunch of methods to
perform in-place modifications. Looks like I stuck, however.

You have to implement only the operations you actually use. So to
save yourself drudge-work, use fewer operations. ;-)
 
C

Chris Mellon

Thanks! I'd missed that thread, googling found it but it didn't look
noteworthy at first glance. I've not yet read the entire thread, but
I did see a reference to PEP 203.

) So, given the expression:
)
) x += y
)
) The object `x' is loaded, then `y' is added to it, and the
) resulting object is stored back in the original place.

That agrees with what I'm seeing, all right. The problem is, the
resulting object has a different type, which seems to violate the
spirit of a later paragraph:

The phrasing is a little awkward. Instead of "store" say "bound to the
same name as"
) Writing the above expression as
)
) <x> <operator>= <y>
)
) is both more readable and less error prone, because it is
) instantly obvious to the reader that it is <x> that is being
) changed, and not <x> that is being replaced by something almost,
) but not quite, entirely unlike <x>.

And that's my complaint. The value in <zed> is being replaced by
something almost, but not quite, identical to the original value.
Python's internal implementation of __iadd__ for <int> isn't returning
<self>, it's returning a new value belonging to the super-class. My
whole point is overloading <int> was that I'd hoped to avoid having to
write a bunch of methods to perform in-place modifications. Looks
like I stuck, however.

Remember that in Python, name binding (which is to say, pure
assignment) is never a mutating operation. It's purely internal to the
namespace it occurs in. So even when augmented assignment returns
self, it still results in a normal Python assignment.

You're going to be struggling against the grain trying to implement a
mutable int anyway, you won't be able to make "foo = 10" mutate the
int, and even if you do create one you probably don't want it to
return true for isinstance(foo, int).
 
M

MonkeeSage

Thanks! I'd missed that thread, googling found it but it didn't look
noteworthy at first glance. I've not yet read the entire thread, but
I did see a reference to PEP 203.

) So, given the expression:
)
) x += y
)
) The object `x' is loaded, then `y' is added to it, and the
) resulting object is stored back in the original place.

That agrees with what I'm seeing, all right. The problem is, the
resulting object has a different type, which seems to violate the
spirit of a later paragraph:

) Writing the above expression as
)
) <x> <operator>= <y>
)
) is both more readable and less error prone, because it is
) instantly obvious to the reader that it is <x> that is being
) changed, and not <x> that is being replaced by something almost,
) but not quite, entirely unlike <x>.

And that's my complaint. The value in <zed> is being replaced by
something almost, but not quite, identical to the original value.
Python's internal implementation of __iadd__ for <int> isn't returning
<self>, it's returning a new value belonging to the super-class. My
whole point is overloading <int> was that I'd hoped to avoid having to
write a bunch of methods to perform in-place modifications. Looks
like I stuck, however.

I've wondered about this myself. Seems to me, to prevent clobbering
subclasses, __iadd__ (and all of the integer and float and whatever)
methods that return new instances, should work like this (obviously I
mean in the C backend, this is just to show the behavior):

def __iadd__(self, other):
return self.__class__(self + other)

Regards,
Jordan
 
G

Gabriel Genellina

I've wondered about this myself. Seems to me, to prevent clobbering
subclasses, __iadd__ (and all of the integer and float and whatever)
methods that return new instances, should work like this (obviously I
mean in the C backend, this is just to show the behavior):

def __iadd__(self, other):
return self.__class__(self + other)

This would slow down *all* of Python, and is only useful for those who
actually inherit from some builtin class (not so common)
 
M

MonkeeSage

This would slow down *all* of Python, and is only useful for those who
actually inherit from some builtin class (not so common)

I understand why it doesn't. It just *seems* like it should work that
way when you first run into it (and has bitten me a couple times
before). But then, I'm not Dutch. :)

Regard,
Jordan
 
A

A.T.Hofkamp

And that's my complaint. The value in <zed> is being replaced by
something almost, but not quite, identical to the original value.
Python's internal implementation of __iadd__ for <int> isn't returning
<self>, it's returning a new value belonging to the super-class. My
whole point is overloading <int> was that I'd hoped to avoid having to
write a bunch of methods to perform in-place modifications. Looks
like I stuck, however.

I think you don't want this.

Suppose I keep track of addition information (eg a boolean "is_even = value ==
value//2") Since the base class doesn't know about this, it may return an
incorrect instance.

Albert
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top