This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: class derived from float evaporates under +=
Type: Stage:
Components: Interpreter Core Versions: Python 2.5
process
Status: closed Resolution: wont fix
Dependencies: Superseder:
Assigned To: Nosy List: doko, georg.brandl, jimjjewett, josiahcarlson
Priority: normal Keywords:

Created on 2007-01-11 23:49 by doko, last changed 2022-04-11 14:56 by admin. This issue is now closed.

Messages (5)
msg30983 - (view) Author: Matthias Klose (doko) * (Python committer) Date: 2007-01-11 23:49
[forwarded from http://bugs.debian.org/345373]

There seems to be a bug in classes derived from float.

For instance, consider the following:

>>> class Float(float):
...     def __init__(self, v):
...             float.__init__(self, v)
...             self.x = 1
...
>>> a = Float(2.0)
>>> b = Float(3.0)
>>> type(a)
<class '__main__.Float'>
>>> type(b)
<class '__main__.Float'>
>>> a += b
>>> type(a)
<type 'float'>

Now,  the type of a has silently changed.   It was a Float, a derived class with
all kinds of properties, and it became a float -- a plain vanilla number.

My understanding is that this is incorrect, and certainly unexpected.
If it *is* correct, it certainly deserves mention somewhere in the documentation.

It seems that   Float.__iadd__(a, b) should be called.
This defaults to float.__iadd__(a, b), which should increment the float
part of the object while leaving the rest intact.

A possible explanation for this problem is that float.__iadd__ is not actually
defined, and so it falls through to
a = float.__add__(a, b), which assigns a float to a.

This interpretation seems to be correct, as one can add a destructor to the Float class:

>>> class FloatD(float):
...     def __init__(self, v):
...             float.__init__(self, v)
...             self.x = 1
...     def __del__(self):
...             print 'Deleting FloatD class, losing x=', self.x
...
>>> a = FloatD(2.0)
>>> b = FloatD(3.0)
>>> a += b
Deleting FloatD class, losing x= 1
>>>
msg30984 - (view) Author: Jim Jewett (jimjjewett) Date: 2007-01-12 21:26
Python float objects are immutable and can be shared. 
Therefore, their values cannot be modified -- which is why it falls back to not-in-place assignment.
msg30985 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2007-01-13 17:57
You don't need augmented assign for that, just doing "a+b" will give you a float too.
msg30986 - (view) Author: Josiah Carlson (josiahcarlson) * (Python triager) Date: 2007-01-16 17:40
The current behavior is as designed.  Not a bug.  Suggested move to RFE or close as "Not a bug".

There has been discussion on either the python-dev or python-3000 mailing lists discussing how subclasses of builtin types (int, long, float, str, unicode, list, tuple, ...) should behave when confronted with one of a set of "standard" operators.  While there has been general "it would be nice" if 'a + b' produced 'type(a)(a + b)' on certain occasions, this would change the semantics of all such operations in a backwards incompatible way (so has not been implemented).

If you want to guarantee such behavior (without writing all of the __special__ methods) I would suggest that you instead create a __getattr__ method to automatically handle the coercion back into your subtype.
msg30987 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2007-01-17 09:14
Okay, closing as "Won't fix". If you still think this should be done differently, please open a feature request.
History
Date User Action Args
2022-04-11 14:56:22adminsetgithub: 44444
2007-01-11 23:49:10dokocreate