Issue531355
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.
Created on 2002-03-18 14:32 by aj_siegel, last changed 2022-04-10 16:05 by admin. This issue is now closed.
Messages (9) | |||
---|---|---|---|
msg9762 - (view) | Author: Arthur Siegel (aj_siegel) | Date: 2002-03-18 14:32 | |
I had presented this on tutor and python-list: class Complex(complex): def __mul__(self,other): other=Complex(other) t = complex.__mul__(self,other) return Complex(t.real,t.imag) __rmul__ = __mul__ def __add__(self,other): other=Complex(other) return Complex(self.real.__add__ (other.real),self.imag.__add__(other.imag)) __radd__ = __add__ Then: print type(Complex(5,4) * 7) >><class '__main__.Complex'> print type(7 * Complex(5,4)) >><class '__main__.Complex'> print type(Complex(5,4) + 7) >><class '__main__.Complex'> But: print type(7 + Complex(5,4)) >><type 'complex'> Danny Yoo, after looking into it pretty deeply - and going to the docs and source gace me this advice. "In any case, this is definitely a bug in the documentation. Arthur, bring it up on comp.lang.python and Sourceforge again. Someone should really look at your example, since it does seem serious... if not a little obscure. *grin* " |
|||
msg9763 - (view) | Author: Guido van Rossum (gvanrossum) * | Date: 2002-03-18 14:49 | |
Logged In: YES user_id=6380 You're right, something's weird. I'll add this to my list. |
|||
msg9764 - (view) | Author: Guido van Rossum (gvanrossum) * | Date: 2002-03-23 03:18 | |
Logged In: YES user_id=6380 It seems that * is the exception -- all other operators (+, -, /, **) return the type of the left operand. It gets even weirder if we change the left operand from 7 to 7.0 -- then * is no longer an exception and returns a complex like all other operators! The weirdness is in int_mul. If the right argument is not an int but a sequence that implements the sq_repeat slot, it invokes that. But if you create a class that defines __mul__, that implements the sequence repeat slot! (Python doesn't know if you intend to implement a seqence or a number, when you define a __mul__ method, so it maps both the nb_multiply and the sq_repeat slots to the __mul__ method). So 7 + Complex() takes the path through int_mul that calls the Complex.__mul__ , and that's why you get a Complex value back. Floats can't be used in the sequence repeat operator, so its multiply is "normal". But wait...! There's another mystery. Ints don't know how to add themselves to complex numbers! So why wouldn't 7+Complex() use the normal pattern of (a) try the left operand, (b) if that returns NotImplemented, try the right operand? The answer is that complex numbers implement coercion! And in that case, step (b) is modified to (b) ask either operand to perform a coercion, and if it succeeds, ask the left operand of the resulting coerced pair to perform the operation. So complex coerces the int to a plain complex, and then invokes the plain complex's add/mul/etc. operation. Solution: add the following to your Complex class: def __coerce__(self, other): x = complex.__coerce__(self, other) if x is NotImplemented: return x a, b = x return Complex(a), Complex(b) I don't think I want to do anything to fix this, although I think I'll pass it on to Fred for documentation (not that I expect him to be in a hurry to fix it either, given the subtlety of the issues). In the long run, I think complex should stop using coercion and start behaving like a "new-style" number like all the other numeric types. That should fix the second mystery. Also, in the long run, the sq_repeat and sq_concat slots should be deprecated and instead sequences should implement multiply and add operations. Then the funny business in int_mul could be taken out and the first mystery would disappear. |
|||
msg9765 - (view) | Author: Arthur Siegel (aj_siegel) | Date: 2002-03-25 00:24 | |
Logged In: YES user_id=248775 Guido - Thanks for your attention to my report. Another bit of suprise with operator overriding in a subclass of complex: from __future__ import division class Complex(complex): def __div__(self,other): t=complex.__div__(self,other) return Complex(t.real,t.imag) a=Complex(5,4) b=Complex(1,7) >> <type 'complex'> But: everything the same *without* calling from __future__ import division print type(a/b) >><class '__main__.Complex'> Based your analysis of the previous issue(which I follow only in broad outline), I have a sense of what's happening. My general sense, though, is that this issue is in some sense more of a problem than the other. Don't think anyone will expect a change in behavior here based on the from __future__ call. Not that subbing complex is a common pursuit - but couldn't this actually break working code in a very unanticpated way, eventually. Obviously not a big issue if the other changes you see happening with complex coercian kick in first, and in fact those changes - as I suspect - would prevent a different return type based on which way int/int is toggled. Art |
|||
msg9766 - (view) | Author: Arthur Siegel (aj_siegel) | Date: 2002-03-25 01:11 | |
Logged In: YES user_id=248775 Have just re-read my submission - and in addition to my usual quota of typos I see I left out something that could confuse what I am trying to bring to your attention. The gist, I am sure you will see, is that type(a/b), where a and b are of a class derived from complex, will change based on whether from __future__ import division is or is not called. And I am assuming that behavior is unanticipated. And I assuming there is no reason to submit this a a bug report separate from this thread. Art |
|||
msg9767 - (view) | Author: Guido van Rossum (gvanrossum) * | Date: 2002-03-25 15:13 | |
Logged In: YES user_id=6380 If you want to override division in a complex subclass, you should define both __truediv__ and __div__, as well as __rtruediv__ and __rdiv__. You can do this by saying __truediv__ = __div__, of course. |
|||
msg9768 - (view) | Author: Arthur Siegel (aj_siegel) | Date: 2002-03-25 15:20 | |
Logged In: YES user_id=248775 Knew I'd embarass myself soon enough in this company. Found the __truediv__ answer on the train into work. Came here hoping to catch it, before you caught me. Too late. Thanks again - oops for the false alarm. Art |
|||
msg9769 - (view) | Author: Neal Norwitz (nnorwitz) * | Date: 2002-09-06 22:52 | |
Logged In: YES user_id=33168 Guido, Fred, is there anything to be done or should this be closed? |
|||
msg9770 - (view) | Author: Guido van Rossum (gvanrossum) * | Date: 2002-09-06 23:35 | |
Logged In: YES user_id=6380 This is fixed in 2.3. Can't remember if it was fixed in 2.2 branch, don't care. |
History | |||
---|---|---|---|
Date | User | Action | Args |
2022-04-10 16:05:06 | admin | set | github: 36275 |
2002-03-18 14:32:27 | aj_siegel | create |