Skip to main content

Objects/complexobject.c (part 9)

Source:

cpython 3.14 @ ab2d84fe1023/Objects/complexobject.c

This annotation covers complex number output and conversion. See objects_complexobject8_detail for complex.__new__, arithmetic operations, and __hash__.

Map

LinesSymbolRole
1-80complex.__repr__ / __str__Format as (a+bj) or bj
81-160complex.__format__Format spec for real and imaginary parts
161-240complex.conjugateReturn a - bj
241-320complex.__abs__sqrt(a² + b²) with overflow protection
321-500PyComplex_AsCComplexExtract Py_complex from any numeric type

Reading

complex.__repr__

// CPython: Objects/complexobject.c:480 complex_repr
static PyObject *
complex_repr(PyComplexObject *v)
{
Py_complex c = v->cval;
char buf[256];
if (c.real == 0.) {
PyOS_snprintf(buf, sizeof(buf), "%gj", c.imag);
} else {
PyOS_snprintf(buf, sizeof(buf), "(%g%+gj)", c.real, c.imag);
}
return PyUnicode_FromString(buf);
}

When the real part is zero, the complex number is formatted as bj (no parentheses). Otherwise it is (a+bj) or (a-bj). The %+g format always prints the sign, producing (1+2j) and (1-2j).

complex.__abs__

// CPython: Objects/complexobject.c:540 complex_abs
static PyObject *
complex_abs(PyComplexObject *v)
{
double result;
Py_BEGIN_ALLOW_THREADS
result = _Py_c_abs(v->cval);
Py_END_ALLOW_THREADS
if (result == Py_HUGE_VAL && !Py_IS_INFINITY(v->cval.real)
&& !Py_IS_INFINITY(v->cval.imag)) {
PyErr_SetString(PyExc_OverflowError, "absolute value too large");
return NULL;
}
return PyFloat_FromDouble(result);
}

_Py_c_abs is hypot(real, imag), which is numerically stable and avoids intermediate overflow. The overflow check catches the case where neither component is infinite but the hypothenuse overflows double.

complex.conjugate

// CPython: Objects/complexobject.c:570 complex_conjugate
static PyObject *
complex_conjugate(PyObject *self, PyObject *Py_UNUSED(ignored))
{
Py_complex c = ((PyComplexObject *)self)->cval;
c.imag = -c.imag;
return PyComplex_FromCComplex(c);
}

(3+4j).conjugate() returns (3-4j). The real part is unchanged; the imaginary part is negated. Conjugates are used in division: a/b = a * conj(b) / abs(b)².

PyComplex_AsCComplex

// CPython: Objects/complexobject.c:380 PyComplex_AsCComplex
Py_complex
PyComplex_AsCComplex(PyObject *op)
{
Py_complex cv;
if (PyComplex_Check(op)) {
return ((PyComplexObject *)op)->cval;
}
/* Try __complex__ */
PyObject *newop = _PyObject_LookupSpecial(op, &_Py_ID(__complex__));
if (newop != NULL) {
PyObject *r = PyObject_CallNoArgs(newop);
/* extract from r */
...
}
/* Fall back to __float__ */
double x = PyFloat_AsDouble(op);
cv.real = x; cv.imag = 0.;
return cv;
}

Any object with __complex__ or __float__ can be used where a complex is expected. The fallback produces a complex with zero imaginary part, so complex(3) and complex(3.0) both yield (3+0j).

gopy notes

complex.__repr__ is in objects/complex.go. complex.__abs__ calls math.Hypot. complex.conjugate creates a new objects.Complex with negated imaginary part. PyComplex_AsCComplex tries __complex__ via objects.LookupSpecial then falls back to objects.AsFloat.