safe conversion of python object to C long

22 views
Skip to first unread message

Vincent Delecroix

unread,
May 3, 2015, 4:47:48 PM5/3/15
to sage-s...@googlegroups.com, Jeroen Demeyer
Hello,

How do we convert Python object to a C long in Cython? The following
does not work properly as rationals or float gets converted (to their floor)

def f(u):
cdef long u_long = u

the following does

def long f(u):
cdef long u_long = u
if u != u_long:
raise TypeError

but I do not find it very clean.

Thanks,
Vincent

Jeroen Demeyer

unread,
May 3, 2015, 4:52:31 PM5/3/15
to sage-s...@googlegroups.com
On 2015-05-03 22:47, Vincent Delecroix wrote:
> Hello,
>
> How do we convert Python object to a C long in Cython? The following
> does not work properly as rationals or float gets converted (to their floor)
>
> def f(u):
> cdef long u_long = u

Well, Cython gave you what you asked for :-)

Cython considers C long (or other C integral types I guess) to
correspond to Python "int" or "long". So your code is really the Cython
version of

u_long = int(u)

which does indeed return the floor (analogous to floats, so this is not
a bug in itself).

What you want here is __index__:

sage: (2/3).__index__()
TypeError: rational is not an integer

In Cython, you call PyNumber_Index():

from cpython.number cimport PyNumber_Index
def f(u):
cdef long u_long = PyNumber_Index(u)


Jeroen.

Vincent Delecroix

unread,
May 3, 2015, 5:04:09 PM5/3/15
to sage-s...@googlegroups.com
On 03/05/15 22:52, Jeroen Demeyer wrote:
> On 2015-05-03 22:47, Vincent Delecroix wrote:
>> Hello,
>>
>> How do we convert Python object to a C long in Cython? The following
>> does not work properly as rationals or float gets converted (to their
>> floor)
>>
> In Cython, you call PyNumber_Index():
>
> from cpython.number cimport PyNumber_Index
> def f(u):
> cdef long u_long = PyNumber_Index(u)

Thanks!

If u is an instance of an extension class that properly defines
__index__, does the above call avoids the creation of an intermediate
Python int? I wonder because its signature is

PyObject* PyNumber_Index(PyObject *o)

If not, then the following would be faster for u being a Sage integer
isn't it

def f(u):
if type(u) is Integer:
if mpz_fits_slong_p((<Integer>u).value):
u_long = mpz_get_si((<Integer>u).value)
...

Vincent

Jeroen Demeyer

unread,
May 3, 2015, 5:17:39 PM5/3/15
to sage-s...@googlegroups.com
On 2015-05-03 23:04, Vincent Delecroix wrote:
> If u is an instance of an extension class that properly defines
> __index__, does the above call avoids the creation of an intermediate
> Python int?
No, there will be a Python int created and I don't think it is possible
to skip this in Python.
Reply all
Reply to author
Forward
0 new messages