>>> class test(int):
pass
Now let's test it:
>>> zed=test(0)
>>> zed.__class__
<class '__main__.test'>
>>> zed
0
So far, so good. Now let's try incrementing:
>>> zed+=1
>>> zed
1
>>> zed.__class__
<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
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.
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. ;-)
--
Neil Cerutti
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).
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
> 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)
--
Gabriel Genellina
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
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