]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Issue #5211: Fix complex type to avoid implicit calls to
authorMark Dickinson <dickinsm@gmail.com>
Sun, 21 Feb 2010 12:57:35 +0000 (12:57 +0000)
committerMark Dickinson <dickinsm@gmail.com>
Sun, 21 Feb 2010 12:57:35 +0000 (12:57 +0000)
complex.__coerce__.  Thanks Meador Inge for the patch.

Doc/reference/datamodel.rst
Lib/test/test_complex.py
Misc/NEWS
Objects/complexobject.c

index 0dc41878d4fc8a50fb6c0ec476fb14146f350c22..25427044e2fac559ff4df093c399fa6fba408ef0 100644 (file)
@@ -2271,13 +2271,15 @@ will not be supported.
 *
 
   In the current implementation, the built-in numeric types :class:`int`,
-  :class:`long` and :class:`float` do not use coercion; the type :class:`complex`
-  however does use coercion for binary operators and rich comparisons, despite
-  the above rules.  The difference can become apparent when subclassing these
-  types.  Over time, the type :class:`complex` may be fixed to avoid coercion.
+  :class:`long`, :class:`float`, and :class:`complex` do not use coercion.
   All these types implement a :meth:`__coerce__` method, for use by the built-in
   :func:`coerce` function.
 
+  .. versionchanged:: 2.7
+
+     The complex type no longer makes implicit calls to the :meth:`__coerce__`
+     method for mixed-type binary arithmetic operations.
+
 
 .. _context-managers:
 
index 199caf08fdaeaed603ea59051b5c3af33cdb5cbf..2cf9a9e15dd1d611f4c68c99b46d46b8571108a3 100644 (file)
@@ -358,6 +358,61 @@ class ComplexTest(unittest.TestCase):
         self.assertAlmostEqual(complex(complex1(1j)), 2j)
         self.assertRaises(TypeError, complex, complex2(1j))
 
+    def test_subclass(self):
+        class xcomplex(complex):
+            def __add__(self,other):
+                return xcomplex(complex(self) + other)
+            __radd__ = __add__
+
+            def __sub__(self,other):
+                return xcomplex(complex(self) + other)
+            __rsub__ = __sub__
+
+            def __mul__(self,other):
+                return xcomplex(complex(self) * other)
+            __rmul__ = __mul__
+
+            def __div__(self,other):
+                return xcomplex(complex(self) / other)
+
+            def __rdiv__(self,other):
+                return xcomplex(other / complex(self))
+
+            __truediv__ = __div__
+            __rtruediv__ = __rdiv__
+
+            def __floordiv__(self,other):
+                return xcomplex(complex(self) // other)
+
+            def __rfloordiv__(self,other):
+                return xcomplex(other // complex(self))
+
+            def __pow__(self,other):
+                return xcomplex(complex(self) ** other)
+
+            def __rpow__(self,other):
+                return xcomplex(other ** complex(self) )
+
+            def __mod__(self,other):
+                return xcomplex(complex(self) % other)
+
+            def __rmod__(self,other):
+                return xcomplex(other % complex(self))
+
+        infix_binops = ('+', '-', '*', '**', '%', '//', '/')
+        xcomplex_values = (xcomplex(1), xcomplex(123.0),
+                           xcomplex(-10+2j), xcomplex(3+187j),
+                           xcomplex(3-78j))
+        test_values = (1, 123.0, 10-19j, xcomplex(1+2j),
+                       xcomplex(1+87j), xcomplex(10+90j))
+
+        for op in infix_binops:
+            for x in xcomplex_values:
+                for y in test_values:
+                    a = 'x %s y' % op
+                    b = 'y %s x' % op
+                    self.assertTrue(type(eval(a)) is type(eval(b)) is xcomplex)
+
     def test_hash(self):
         for x in xrange(-30, 30):
             self.assertEqual(hash(x), hash(complex(x, 0)))
index 57506050a6d9b8c80ac19fd94ee6042d6e60fcbd..92111376101462f2cc45254edc1747793316699a 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,9 @@ What's New in Python 2.7 alpha 4?
 Core and Builtins
 -----------------
 
+- Issue #5211: the complex type no longer uses implicit coercion in
+  mixed-type binary arithmetic operations.
+
 Library
 -------
 
index 3317106f1880c4913fcca36b8b4f4b660fcc2c23..da2075a386f8bd020e2776845d828c070c303f62 100644 (file)
@@ -513,43 +513,54 @@ to_complex(PyObject **pobj, Py_complex *pc)
                
 
 static PyObject *
-complex_add(PyComplexObject *v, PyComplexObject *w)
+complex_add(PyObject *v, PyObject *w)
 {
        Py_complex result;
+       Py_complex a, b;
+       TO_COMPLEX(v, a);
+       TO_COMPLEX(w, b);
        PyFPE_START_PROTECT("complex_add", return 0)
-       result = c_sum(v->cval,w->cval);
+       result = c_sum(a, b);
        PyFPE_END_PROTECT(result)
        return PyComplex_FromCComplex(result);
 }
 
 static PyObject *
-complex_sub(PyComplexObject *v, PyComplexObject *w)
+complex_sub(PyObject *v, PyObject *w)
 {
-       Py_complex result;
+        Py_complex result;
+       Py_complex a, b;
+       TO_COMPLEX(v, a);
+       TO_COMPLEX(w, b);;
        PyFPE_START_PROTECT("complex_sub", return 0)
-       result = c_diff(v->cval,w->cval);
+       result = c_diff(a, b);
        PyFPE_END_PROTECT(result)
        return PyComplex_FromCComplex(result);
 }
 
 static PyObject *
-complex_mul(PyComplexObject *v, PyComplexObject *w)
+complex_mul(PyObject *v, PyObject *w)
 {
        Py_complex result;
+       Py_complex a, b;
+       TO_COMPLEX(v, a);
+       TO_COMPLEX(w, b);
        PyFPE_START_PROTECT("complex_mul", return 0)
-       result = c_prod(v->cval,w->cval);
+       result = c_prod(a, b);
        PyFPE_END_PROTECT(result)
        return PyComplex_FromCComplex(result);
 }
 
 static PyObject *
-complex_div(PyComplexObject *v, PyComplexObject *w)
+complex_div(PyObject *v, PyObject *w)
 {
        Py_complex quot;
-
+       Py_complex a, b;
+       TO_COMPLEX(v, a);
+       TO_COMPLEX(w, b);
        PyFPE_START_PROTECT("complex_div", return 0)
        errno = 0;
-       quot = c_quot(v->cval,w->cval);
+       quot = c_quot(a, b);
        PyFPE_END_PROTECT(quot)
        if (errno == EDOM) {
                PyErr_SetString(PyExc_ZeroDivisionError, "complex division");
@@ -559,10 +570,12 @@ complex_div(PyComplexObject *v, PyComplexObject *w)
 }
 
 static PyObject *
-complex_classic_div(PyComplexObject *v, PyComplexObject *w)
+complex_classic_div(PyObject *v, PyObject *w)
 {
        Py_complex quot;
-
+       Py_complex a, b;
+       TO_COMPLEX(v, a);
+       TO_COMPLEX(w, b);
        if (Py_DivisionWarningFlag >= 2 &&
            PyErr_Warn(PyExc_DeprecationWarning,
                       "classic complex division") < 0)
@@ -570,7 +583,7 @@ complex_classic_div(PyComplexObject *v, PyComplexObject *w)
 
        PyFPE_START_PROTECT("complex_classic_div", return 0)
        errno = 0;
-       quot = c_quot(v->cval,w->cval);
+       quot = c_quot(a, b);
        PyFPE_END_PROTECT(quot)
        if (errno == EDOM) {
                PyErr_SetString(PyExc_ZeroDivisionError, "complex division");
@@ -580,47 +593,51 @@ complex_classic_div(PyComplexObject *v, PyComplexObject *w)
 }
 
 static PyObject *
-complex_remainder(PyComplexObject *v, PyComplexObject *w)
+complex_remainder(PyObject *v, PyObject *w)
 {
        Py_complex div, mod;
-
+       Py_complex a, b;
+       TO_COMPLEX(v, a);
+       TO_COMPLEX(w, b);
        if (PyErr_Warn(PyExc_DeprecationWarning,
                       "complex divmod(), // and % are deprecated") < 0)
                return NULL;
 
        errno = 0;
-       div = c_quot(v->cval,w->cval); /* The raw divisor value. */
+       div = c_quot(a, b); /* The raw divisor value. */
        if (errno == EDOM) {
                PyErr_SetString(PyExc_ZeroDivisionError, "complex remainder");
                return NULL;
        }
        div.real = floor(div.real); /* Use the floor of the real part. */
        div.imag = 0.0;
-       mod = c_diff(v->cval, c_prod(w->cval, div));
+       mod = c_diff(a, c_prod(b, div));
 
        return PyComplex_FromCComplex(mod);
 }
 
 
 static PyObject *
-complex_divmod(PyComplexObject *v, PyComplexObject *w)
+complex_divmod(PyObject *v, PyObject *w)
 {
        Py_complex div, mod;
        PyObject *d, *m, *z;
-
+       Py_complex a, b;
+       TO_COMPLEX(v, a);
+       TO_COMPLEX(w, b);
        if (PyErr_Warn(PyExc_DeprecationWarning,
                       "complex divmod(), // and % are deprecated") < 0)
                return NULL;
 
        errno = 0;
-       div = c_quot(v->cval,w->cval); /* The raw divisor value. */
+       div = c_quot(a, b); /* The raw divisor value. */
        if (errno == EDOM) {
                PyErr_SetString(PyExc_ZeroDivisionError, "complex divmod()");
                return NULL;
        }
        div.real = floor(div.real); /* Use the floor of the real part. */
        div.imag = 0.0;
-       mod = c_diff(v->cval, c_prod(w->cval, div));
+       mod = c_diff(a, c_prod(b, div));
        d = PyComplex_FromCComplex(div);
        m = PyComplex_FromCComplex(mod);
        z = PyTuple_Pack(2, d, m);
@@ -638,8 +655,7 @@ complex_pow(PyObject *v, PyObject *w, PyObject *z)
        Py_complex a, b;
        TO_COMPLEX(v, a);
        TO_COMPLEX(w, b);
-
-       if (z!=Py_None) {
+       if (z!=Py_None) {
                PyErr_SetString(PyExc_ValueError, "complex modulo");
                return NULL;
        }
@@ -668,10 +684,12 @@ complex_pow(PyObject *v, PyObject *w, PyObject *z)
 }
 
 static PyObject *
-complex_int_div(PyComplexObject *v, PyComplexObject *w)
+complex_int_div(PyObject *v, PyObject *w)
 {
        PyObject *t, *r;
-       
+       Py_complex a, b;
+       TO_COMPLEX(v, a);
+       TO_COMPLEX(w, b);
        if (PyErr_Warn(PyExc_DeprecationWarning,
                       "complex divmod(), // and % are deprecated") < 0)
                return NULL;
@@ -1282,7 +1300,8 @@ PyTypeObject PyComplex_Type = {
        PyObject_GenericGetAttr,                /* tp_getattro */
        0,                                      /* tp_setattro */
        0,                                      /* tp_as_buffer */
-       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES |
+               Py_TPFLAGS_BASETYPE,            /* tp_flags */
        complex_doc,                            /* tp_doc */
        0,                                      /* tp_traverse */
        0,                                      /* tp_clear */