diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 8a185486fe44f1..fd5d0c47ea793e 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -276,7 +276,7 @@ sub-slots +---------------------------------------------------------+-----------------------------------+---------------+ | :c:member:`~PyNumberMethods.nb_int` | :c:type:`unaryfunc` | __int__ | +---------------------------------------------------------+-----------------------------------+---------------+ - | :c:member:`~PyNumberMethods.nb_reserved` | void * | | + | :c:member:`~PyNumberMethods.nb_complex` | :c:type:`unaryfunc` | __complex__ | +---------------------------------------------------------+-----------------------------------+---------------+ | :c:member:`~PyNumberMethods.nb_float` | :c:type:`unaryfunc` | __float__ | +---------------------------------------------------------+-----------------------------------+---------------+ @@ -2263,7 +2263,7 @@ Number Object Structures binaryfunc nb_xor; binaryfunc nb_or; unaryfunc nb_int; - void *nb_reserved; + unaryfunc nb_complex; unaryfunc nb_float; binaryfunc nb_inplace_add; @@ -2297,11 +2297,6 @@ Number Object Structures ``Py_NotImplemented``, if another error occurred they must return ``NULL`` and set an exception. - .. note:: - - The :c:member:`~PyNumberMethods.nb_reserved` field should always be ``NULL``. It - was previously called :c:member:`!nb_long`, and was renamed in - Python 3.0.1. .. c:member:: binaryfunc PyNumberMethods.nb_add .. c:member:: binaryfunc PyNumberMethods.nb_subtract @@ -2320,7 +2315,7 @@ Number Object Structures .. c:member:: binaryfunc PyNumberMethods.nb_xor .. c:member:: binaryfunc PyNumberMethods.nb_or .. c:member:: unaryfunc PyNumberMethods.nb_int -.. c:member:: void *PyNumberMethods.nb_reserved +.. c:member:: unaryfunc PyNumberMethods.nb_complex .. c:member:: unaryfunc PyNumberMethods.nb_float .. c:member:: binaryfunc PyNumberMethods.nb_inplace_add .. c:member:: binaryfunc PyNumberMethods.nb_inplace_subtract diff --git a/Include/cpython/object.h b/Include/cpython/object.h index f0f61796cd3ec8..9c4d18d0fa889c 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -79,7 +79,7 @@ typedef struct { binaryfunc nb_xor; binaryfunc nb_or; unaryfunc nb_int; - void *nb_reserved; /* the slot formerly known as nb_long */ + unaryfunc nb_complex; /* the slot formerly known as nb_long */ unaryfunc nb_float; binaryfunc nb_inplace_add; diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index b1102984cb5e9e..93ef8d541acd88 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -3043,7 +3043,7 @@ static PyNumberMethods delta_as_number = { 0, /*nb_xor*/ 0, /*nb_or*/ 0, /*nb_int*/ - 0, /*nb_reserved*/ + 0, /*nb_complex*/ 0, /*nb_float*/ 0, /*nb_inplace_add*/ 0, /*nb_inplace_subtract*/ diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 26f68691e44f83..66f43f55fd1713 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3539,7 +3539,7 @@ static PyNumberMethods matmulType_as_number = { 0, /* nb_xor */ 0, /* nb_or */ 0, /* nb_int */ - 0, /* nb_reserved */ + 0, /* nb_complex */ 0, /* nb_float */ 0, /* nb_inplace_add */ 0, /* nb_inplace_subtract */ diff --git a/Objects/boolobject.c b/Objects/boolobject.c index a88a8ad0cfd560..0ebe42633bd99b 100644 --- a/Objects/boolobject.c +++ b/Objects/boolobject.c @@ -137,7 +137,7 @@ static PyNumberMethods bool_as_number = { bool_xor, /* nb_xor */ bool_or, /* nb_or */ 0, /* nb_int */ - 0, /* nb_reserved */ + 0, /* nb_complex */ 0, /* nb_float */ 0, /* nb_inplace_add */ 0, /* nb_inplace_subtract */ diff --git a/Objects/clinic/complexobject.c.h b/Objects/clinic/complexobject.c.h index 58fd4e26871b4d..a08928c8caf1e2 100644 --- a/Objects/clinic/complexobject.c.h +++ b/Objects/clinic/complexobject.c.h @@ -72,24 +72,6 @@ complex___format__(PyComplexObject *self, PyObject *arg) return return_value; } -PyDoc_STRVAR(complex___complex____doc__, -"__complex__($self, /)\n" -"--\n" -"\n" -"Convert this value to exact type complex."); - -#define COMPLEX___COMPLEX___METHODDEF \ - {"__complex__", (PyCFunction)complex___complex__, METH_NOARGS, complex___complex____doc__}, - -static PyObject * -complex___complex___impl(PyComplexObject *self); - -static PyObject * -complex___complex__(PyComplexObject *self, PyObject *Py_UNUSED(ignored)) -{ - return complex___complex___impl(self); -} - PyDoc_STRVAR(complex_new__doc__, "complex(real=0, imag=0)\n" "--\n" @@ -169,4 +151,4 @@ PyDoc_STRVAR(complex_from_number__doc__, #define COMPLEX_FROM_NUMBER_METHODDEF \ {"from_number", (PyCFunction)complex_from_number, METH_O|METH_CLASS, complex_from_number__doc__}, -/*[clinic end generated code: output=188438cc9ae167f7 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a8124d43a8ccef55 input=a9049054013a1b77]*/ diff --git a/Objects/complexobject.c b/Objects/complexobject.c index 787235c63a6be1..0dea7df3ce4512 100644 --- a/Objects/complexobject.c +++ b/Objects/complexobject.c @@ -329,34 +329,44 @@ PyComplex_ImagAsDouble(PyObject *op) static PyObject * try_complex_special_method(PyObject *op) { - PyObject *f; - - f = _PyObject_LookupSpecial(op, &_Py_ID(__complex__)); - if (f) { - PyObject *res = _PyObject_CallNoArgs(f); - Py_DECREF(f); - if (!res || PyComplex_CheckExact(res)) { - return res; - } - if (!PyComplex_Check(res)) { - PyErr_Format(PyExc_TypeError, - "__complex__ returned non-complex (type %.200s)", - Py_TYPE(res)->tp_name); - Py_DECREF(res); - return NULL; - } - /* Issue #29894: warn if 'res' not of exact type complex. */ - if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, - "__complex__ returned non-complex (type %.200s). " - "The ability to return an instance of a strict subclass of complex " - "is deprecated, and may be removed in a future version of Python.", - Py_TYPE(res)->tp_name)) { - Py_DECREF(res); - return NULL; + PyNumberMethods *m = Py_TYPE(op)->tp_as_number; + PyObject *res = NULL; + + if (m && m->nb_complex) { + res = m->nb_complex(op); + } + else { + PyObject *f = _PyObject_LookupSpecial(op, &_Py_ID(__complex__)); + if (f) { + res = _PyObject_CallNoArgs(f); + Py_DECREF(f); + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "XXX use nb_complex", 1)) { + Py_XDECREF(res); + } } + } + + if (!res || PyComplex_CheckExact(res)) { return res; } - return NULL; + if (!PyComplex_Check(res)) { + PyErr_Format(PyExc_TypeError, + "__complex__ returned non-complex (type %.200s)", + Py_TYPE(res)->tp_name); + Py_DECREF(res); + return NULL; + } + /* Issue #29894: warn if 'res' not of exact type complex. */ + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "__complex__ returned non-complex (type %.200s). " + "The ability to return an instance of a strict subclass of complex " + "is deprecated, and may be removed in a future version of Python.", + Py_TYPE(res)->tp_name)) { + Py_DECREF(res); + return NULL; + } + return res; } Py_complex @@ -740,25 +750,17 @@ complex___format___impl(PyComplexObject *self, PyObject *format_spec) return _PyUnicodeWriter_Finish(&writer); } -/*[clinic input] -complex.__complex__ - -Convert this value to exact type complex. -[clinic start generated code]*/ - static PyObject * -complex___complex___impl(PyComplexObject *self) -/*[clinic end generated code: output=e6b35ba3d275dc9c input=3589ada9d27db854]*/ +complex_complex(PyObject *self) { if (PyComplex_CheckExact(self)) { return Py_NewRef(self); } else { - return PyComplex_FromCComplex(self->cval); + return PyComplex_FromCComplex(((PyComplexObject *)self)->cval); } } - static PyObject * complex_from_string_inner(const char *s, Py_ssize_t len, void *type) { @@ -1160,7 +1162,6 @@ complex_from_number(PyTypeObject *type, PyObject *number) static PyMethodDef complex_methods[] = { COMPLEX_FROM_NUMBER_METHODDEF COMPLEX_CONJUGATE_METHODDEF - COMPLEX___COMPLEX___METHODDEF COMPLEX___GETNEWARGS___METHODDEF COMPLEX___FORMAT___METHODDEF {NULL, NULL} /* sentinel */ @@ -1192,7 +1193,7 @@ static PyNumberMethods complex_as_number = { 0, /* nb_xor */ 0, /* nb_or */ 0, /* nb_int */ - 0, /* nb_reserved */ + complex_complex, /* nb_complex */ 0, /* nb_float */ 0, /* nb_inplace_add */ 0, /* nb_inplace_subtract */ diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 7e14a8ad959590..fd3a72f032396a 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -1857,7 +1857,7 @@ static PyNumberMethods float_as_number = { 0, /* nb_xor */ 0, /* nb_or */ float___trunc___impl, /* nb_int */ - 0, /* nb_reserved */ + 0, /* nb_complex */ float_float, /* nb_float */ 0, /* nb_inplace_add */ 0, /* nb_inplace_subtract */ diff --git a/Objects/longobject.c b/Objects/longobject.c index 4e948940485730..4be2de03e990de 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -6522,7 +6522,7 @@ static PyNumberMethods long_as_number = { long_xor, /*nb_xor*/ long_or, /*nb_or*/ long_long, /*nb_int*/ - 0, /*nb_reserved*/ + 0, /*nb_complex*/ long_float, /*nb_float*/ 0, /* nb_inplace_add */ 0, /* nb_inplace_subtract */ diff --git a/Objects/object.c b/Objects/object.c index 7cc74a8dc0d8eb..41f98db360ecfe 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -2061,7 +2061,7 @@ static PyNumberMethods none_as_number = { 0, /* nb_xor */ 0, /* nb_or */ 0, /* nb_int */ - 0, /* nb_reserved */ + 0, /* nb_complex */ 0, /* nb_float */ 0, /* nb_inplace_add */ 0, /* nb_inplace_subtract */ diff --git a/Objects/setobject.c b/Objects/setobject.c index 66d7fc730c555c..4ca0f428b6c35a 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -2454,7 +2454,7 @@ static PyNumberMethods set_as_number = { set_xor, /*nb_xor*/ set_or, /*nb_or*/ 0, /*nb_int*/ - 0, /*nb_reserved*/ + 0, /*nb_complex*/ 0, /*nb_float*/ 0, /*nb_inplace_add*/ set_isub, /*nb_inplace_subtract*/ diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 88db29e14b0d44..a34b804d3055b1 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -9787,6 +9787,7 @@ SLOT1BIN(slot_nb_xor, nb_xor, __xor__, __rxor__) SLOT1BIN(slot_nb_or, nb_or, __or__, __ror__) SLOT0(slot_nb_int, __int__) +SLOT0(slot_nb_complex, __complex__) SLOT0(slot_nb_float, __float__) SLOT1(slot_nb_inplace_add, __iadd__, PyObject *) SLOT1(slot_nb_inplace_subtract, __isub__, PyObject *) @@ -10667,6 +10668,8 @@ static pytype_slotdef slotdefs[] = { RBINSLOT(__ror__, nb_or, slot_nb_or, "|"), UNSLOT(__int__, nb_int, slot_nb_int, wrap_unaryfunc, "int(self)"), + UNSLOT(__complex__, nb_complex, slot_nb_complex, wrap_unaryfunc, + "complex(self)"), UNSLOT(__float__, nb_float, slot_nb_float, wrap_unaryfunc, "float(self)"), IBSLOT(__iadd__, nb_inplace_add, slot_nb_inplace_add, diff --git a/Objects/weakrefobject.c b/Objects/weakrefobject.c index 9e3da1c3394d5b..aa5c1d6480ea79 100644 --- a/Objects/weakrefobject.c +++ b/Objects/weakrefobject.c @@ -809,7 +809,7 @@ static PyNumberMethods proxy_as_number = { proxy_xor, /*nb_xor*/ proxy_or, /*nb_or*/ proxy_int, /*nb_int*/ - 0, /*nb_reserved*/ + 0, /*nb_complex*/ proxy_float, /*nb_float*/ proxy_iadd, /*nb_inplace_add*/ proxy_isub, /*nb_inplace_subtract*/