Issue 3734: subclassing complex - Python tracker (original) (raw)

Created on 2008-08-29 22:39 by gumtree, last changed 2022-04-11 14:56 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
issue3734.patch mark.dickinson,2009-02-10 23:31
Messages (8)
msg72169 - (view) Author: Blair (gumtree) Date: 2008-08-29 22:39
The following is quoted from the Python docs (ref/numeric_types): "Note: If the right operand's type is a subclass of the left operand's type and that subclass provides the reflected method for the operation, this method will be called before the left operand's non-reflected method. This behavior allows subclasses to override their ancestors' operations." My issue is that the built-in complex type does not respect this rule (see code below). Note that float can be subclassed using the method shown below and the rules are applied correctly. It seems that it is only a problem with complex. class xcomplex( complex ): def __new__(cls,*args,**kwargs): return complex.__new__(cls,*args,**kwargs) def __coerce__(self,other): t = complex.__coerce__(self,other) try: return (self,xcomplex(t[1])) except TypeError: return t def __add__(self,x): return xcomplex( complex.__add__(self,x) ) def __radd__(self,x): return xcomplex( complex.__radd__(self,x) ) print type(z + xz) # gives complex when xcomplex is required
msg81571 - (view) Author: Daniel Diniz (ajaksu2) * (Python triager) Date: 2009-02-10 18:12
Confirmed in trunk. Here's a copy-n-past'able testcase: class xcomplex( complex ): def __new__(cls,*args,**kwargs): return complex.__new__(cls,*args,**kwargs) def __coerce__(self,other): t = complex.__coerce__(self,other) try: return (self,xcomplex(t[1])) except TypeError: return t def __add__(self,x): return xcomplex( complex.__add__(self,x) ) def __radd__(self,x): return xcomplex( complex.__radd__(self,x) ) class xfloat(float): def __new__(cls,*args,**kwargs): return float.__new__(cls,*args,**kwargs) def __coerce__(self,other): t = float.__coerce__(self,other) try: return (self,float(t[1])) except TypeError: return t def __add__(self,x): return xfloat( float.__add__(self,x) ) def __radd__(self,x): return xfloat( float.__radd__(self,x) ) z = 1j xz = xcomplex(1j) f = 1.0 xf = xfloat(1.0) print type(z + xz) print type(f + xf)
msg81584 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2009-02-10 19:21
I'll take a look.
msg81609 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2009-02-10 22:23
So there's a hint about what's happening here at the bottom of the section http://docs.python.org/reference/datamodel.html#id5 of the docs, where it says: """In the current implementation, the built-in numeric types int, long and float do not use coercion; the type complex however does use it. The difference can become apparent when subclassing these types. Over time, the type complex may be fixed to avoid coercion. [...]""" In the OPs example, when z + xz is evaluated, xz is (successfully) coerced to type complex, and then complex.__add__ is called to do the addition as usual. There's definitely (at least) a documentation bug here, given that at the same place as referenced above it says: """New-style classes (those derived from object) never invoke the __coerce__() method in response to a binary operator; the only time __coerce__() is invoked is when the built-in function coerce() is called.""" At the level of the C code, the practical difference between complex and (for example) float is that the float type has Py_TPFLAGS_CHECKTYPES set, and all arithmetic operations do their own conversions. The complex type doesn't set Py_TPFLAGS_CHECKTYPES, and so (contrary to the documentation) relies on complex_coerce to do any conversions.
msg81613 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2009-02-10 23:31
I think this issue comes down to a doc fix, though I've opened issue 5211 for anyone who fancies having a go at removing coercion from the complex type. Here's a doc patch.
msg81614 - (view) Author: Blair (gumtree) Date: 2009-02-11 00:00
While Mark Dickinson's patch fixes the documentation, it does not offer a solution to the original problem, which was rooted in a need to provide special behaviour based on the numeric types. I made the original posting because I hoped that this problem could be resolved.
msg81634 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2009-02-11 08:58
[gumtree] > [...] does not offer > a solution to the original problem, which was rooted in a need to > provide special behaviour based on the numeric types. I made the > original posting because I hoped that this problem could be resolved. Please see issue 5211 for further discussion.
msg81902 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2009-02-13 10:45
Applied doc patch in r69573.
History
Date User Action Args
2022-04-11 14:56:38 admin set github: 47984
2009-02-13 10:45:04 georg.brandl set status: open -> closedresolution: fixedmessages: +
2009-02-11 08:58:41 mark.dickinson set messages: +
2009-02-11 00:00:05 gumtree set messages: +
2009-02-10 23:31:57 mark.dickinson set files: + issue3734.patchassignee: mark.dickinson -> georg.brandlmessages: + keywords: + patchnosy: + georg.brandl
2009-02-10 22:23:05 mark.dickinson set messages: +
2009-02-10 19:21:52 mark.dickinson set assignee: mark.dickinsonmessages: +
2009-02-10 18:12:32 ajaksu2 set nosy: + mark.dickinson, ajaksu2messages: + components: + Interpreter Core, - Noneversions: + Python 2.6, Python 2.7, - Python 2.5
2008-08-29 22:39:09 gumtree create