mirror of
https://github.com/python/cpython.git
synced 2025-09-15 13:16:12 +00:00
Patch #1675423: PyComplex_AsCComplex() now tries to convert an object
to complex using its __complex__() method before falling back to the __float__() method. Therefore, the functions in the cmath module now can operate on objects that define a __complex__() method. (backport)
This commit is contained in:
parent
6f187743ff
commit
2b869943fa
5 changed files with 258 additions and 50 deletions
|
@ -252,12 +252,59 @@ Py_complex
|
|||
PyComplex_AsCComplex(PyObject *op)
|
||||
{
|
||||
Py_complex cv;
|
||||
PyObject *newop = NULL;
|
||||
static PyObject *complex_str = NULL;
|
||||
|
||||
assert(op);
|
||||
/* If op is already of type PyComplex_Type, return its value */
|
||||
if (PyComplex_Check(op)) {
|
||||
return ((PyComplexObject *)op)->cval;
|
||||
}
|
||||
/* If not, use op's __complex__ method, if it exists */
|
||||
|
||||
/* return -1 on failure */
|
||||
cv.real = -1.;
|
||||
cv.imag = 0.;
|
||||
|
||||
if (PyInstance_Check(op)) {
|
||||
/* this can go away in python 3000 */
|
||||
if (PyObject_HasAttrString(op, "__complex__")) {
|
||||
newop = PyObject_CallMethod(op, "__complex__", NULL);
|
||||
if (!newop)
|
||||
return cv;
|
||||
}
|
||||
/* else try __float__ */
|
||||
} else {
|
||||
PyObject *complexfunc;
|
||||
if (!complex_str) {
|
||||
if (!(complex_str = PyString_FromString("__complex__")))
|
||||
return cv;
|
||||
}
|
||||
complexfunc = _PyType_Lookup(op->ob_type, complex_str);
|
||||
/* complexfunc is a borrowed reference */
|
||||
if (complexfunc) {
|
||||
newop = PyObject_CallFunctionObjArgs(complexfunc, op, NULL);
|
||||
if (!newop)
|
||||
return cv;
|
||||
}
|
||||
}
|
||||
|
||||
if (newop) {
|
||||
if (!PyComplex_Check(newop)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"__complex__ should return a complex object");
|
||||
Py_DECREF(newop);
|
||||
return cv;
|
||||
}
|
||||
cv = ((PyComplexObject *)newop)->cval;
|
||||
Py_DECREF(newop);
|
||||
return cv;
|
||||
}
|
||||
/* If neither of the above works, interpret op as a float giving the
|
||||
real part of the result, and fill in the imaginary part as 0. */
|
||||
else {
|
||||
/* PyFloat_AsDouble will return -1 on failure */
|
||||
cv.real = PyFloat_AsDouble(op);
|
||||
cv.imag = 0.;
|
||||
return cv;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue