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