On 12/20/10 1:42 PM, Simon King wrote:
Dear sage-support,

at #10496, David Roe gave me the advice to use PY_TYPE_CHECK rather
than isinstance in Cython files. I did so.

But actually I didn't know PY_TYPE_CHECK at all, and so I have a two
questions:

1) Apparently there are  several PY_... functions. Where can I read
about them?


I see them imported in devel/sage/sage/ext/stdsage.pxi:

-----------------------
cdef extern from "stdsage.h":
    ctypedef void PyObject

    # Global tuple -- useful optimization
    void init_global_empty_tuple()
    object PY_NEW(object t)
    object PY_NEW_SAME_TYPE(object t)

    void* PY_TYPE(object o)
    bint PY_TYPE_CHECK(object o, object t)
    bint PY_TYPE_CHECK_EXACT(object o, object t)

    object IS_INSTANCE(object o, object t)
    void PY_SET_TP_NEW(object t1, object t2)
    bint HAS_DICTIONARY(object o)
    bint PY_IS_NUMERIC(object o)
-----------------------


The stdsage.h file is in devel/sage/c_lib/include/stdsage.h, where we find:

-----------------------
/** Tests whether zzz_obj is of type zzz_type. The zzz_type must be a
 * built-in or extension type. This is just a C++-compatible wrapper
 * for PyObject_TypeCheck.
 */
#define PY_TYPE_CHECK(zzz_obj, zzz_type) \
    (PyObject_TypeCheck((PyObject*)(zzz_obj), (PyTypeObject*)(zzz_type)))
-----------------------

in fact, we find later on:

-----------------------

/** This is exactly the same as isinstance (and does return a Python
 *  bool), but the second argument must be a C-extension type -- so it
 *  can't be a Python class or a list.  If you just want an int return
 *  value, i.e., aren't going to pass this back to Python, just use
 *  PY_TYPE_CHECK.
 */
#define IS_INSTANCE(zzz_obj, zzz_type) \
    PyBool_FromLong(PY_TYPE_CHECK(zzz_obj, zzz_type))
-----------------------


...interpret how you will....




2) Is PY_TYPE_CHECK really quicker than isinstance?

It doesn't seem so, actually.

In testtype.pyx, I wrote
cpdef t1(x):
     return PY_TYPE_CHECK(x,int)
cpdef t2(x):
     return isinstance(x,int)


Then, I got the following timings:
{{{
sage: attach typecheck.pyx
Compiling typecheck.pyx...
sage: t1(5)
False
sage: t1(int(5))
True
sage: t2(5)
False
sage: t2(int(5))
True
sage: timeit("a=t1(5)")
625 loops, best of 3: 218 ns per loop
sage: timeit("a=t2(5)")
625 loops, best of 3: 205 ns per loop
sage: timeit("a=t1(int(5))")
625 loops, best of 3: 416 ns per loop
sage: timeit("a=t2(int(5))")
625 loops, best of 3: 401 ns per loop
}}}

So, actually isinstance is slightly quicker than PY_TYPE_CHECK. Or do
I misunderstand  something?



I notice in the generated C code, Cython is smart and makes isinstance actually call PyInt_Check, which presumably is faster than PY_TYPE_CHECK.

If instead, you are checking for the Integer type, I get faster numbers for PY_TYPE_CHECK than isinstance. I also tried to lessen the effects of python call overhead by running the call in a loop in Cython: http://demo.sagenb.org/home/pub/65/


Thanks,

Jason

--
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/sage-support
URL: http://www.sagemath.org

Reply via email to