Use nb_reserved slot of PyNumberMethods to support complex() method? (original) (raw)
Despite we have complex builtin type - there is no support for them in the PyNumberMethods structure. Then __complex__()
dunder should be implemented as ordinary method. That makes complex initialization relatively expensive wrt one for floats (see also gh-109218: Deprecate weird cases in the complex() constructor by serhiy-storchaka · Pull Request #119620 · python/cpython · GitHub).
Simple benchmarks in my branch wrt main
# a.py
x1 = 1+1j
class c2(complex): ...
x2 = c2()
class c3:
def __complex__(self):
return x1
x3 = c3()
With nb_complex:
$ ./python -m timeit -s 'from a import x1' -unsec 'complex(x1)'
500000 loops, best of 5: 582 nsec per loop
$ ./python -m timeit -s 'from a import x2' -unsec 'complex(x2)'
200000 loops, best of 5: 1.74e+03 nsec per loop
$ ./python -m timeit -s 'from a import x3' -unsec 'complex(x3)'
100000 loops, best of 5: 3.09e+03 nsec per loop
With main:
$ ./python -m timeit -s 'from a import x1' -unsec 'complex(x1)'
500000 loops, best of 5: 659 nsec per loop
$ ./python -m timeit -s 'from a import x2' -unsec 'complex(x2)'
100000 loops, best of 5: 3.25e+03 nsec per loop
$ ./python -m timeit -s 'from a import x3' -unsec 'complex(x3)'
50000 loops, best of 5: 4.32e+03 nsec per loop
There is reserved slot (nb_reserved
), maybe we should use one to implement nb_complex
? (Here is the patch to play with: Add nb_complex slot to PyNumberMethods (was nb_reserved) by skirpichev · Pull Request #2 · skirpichev/cpython · GitHub). Probably, Number Protocol should also include PyNumber_Complex()
function. Edit: note, that PyNumber_Check()
returns 1
for complex numbers.
This shouldn’t break existing code; DeprecationWarning will be emitted, if extension uses ordinary method to implement __complex__()
.
If performance argument isn’t impressive, lets see that docs says about PyNumberMethods: “This structure holds pointers to the functions which an object uses to implement the number protocol.” It’s odd that conversion to complex is not a part of the Number Protocol. (C.f. the numeric ABC.)
Is there arguments to keep nb_reserved
? E.g. it wasn’t helpful in last case when PyNumberMethods was changed (matrix multiplication).