[capi-sig] expy 0.5.2 released

Yingjie Lan lanyjie at yahoo.com
Wed Feb 3 13:21:00 CET 2010


Hi, Thank you very much for making this fantastic 
contrast with Cython. Admittedly, Cython has 
a lot of good things, and it is improved a lot.
The task expy is targeting at is different from
that of Cython, and I hope expy provides more
flexibility when it comes to extend Python.

> >>> in release 0.5.2, expy now supports custom
> exceptions,
> >>> besides all built-in ones, and exception
> handling is made
> >>> easy.
> >>
> >> How does that work? I.e., how do you handle
> exceptions that
> >> occur inside of
> >> the plain string that expy uses to integrate C
> code?
> > 
> > There are several ways to throw exceptions with expy.
> First of all, you
> > can use @throws(...) to throw exceptions based on
> input
> > and output of a function. Another possibility is to
> throw exceptions inside
> > your function implementation, and upon return of your
> code, the wrapper
> > function would return NULL after all necessary
> reference count management,
> > if any exception is thrown by your function
> implementation code. Please
> > also refer to the documentation of expy on exception
> handling here (it also
> > includes how to create a custom exception, and how to
> manage exception
> > inheritance):
> > 
> > http://expy.sourceforge.net/tutorial.html#exception-for-arguments-returns
> 
> 
> Hmm, there's a lot of code in that example. Let's contrast
> that to Cython.
> 
> -------------------------
> MyError = gfield(exception('module1f.MyError',
> ValueError))
> NegError = gfield(exception('module1f.NegEror', MyError))
> -------------------------
> 
> Cython:
> 
>     class MyError(ValueError): pass
>     class NegError(MyError): pass
> 
> 

Yes, this looks much easier, I need to modify the way 
exceptions are defined in expy, after which the 
same thing would be possible with expy. Thanks!
There are many good things to learn from Cython.

> -------------------------
> #'$return': returned value
> @function(int)
> @throws('$return<0', NegError, 'No negatives!')
> @throws('$return>100', ValueError, 'Out of range: %i',
> '$return')
> def range_check(n = int):
>    return "n*n"
> -------------------------
> 
> Cython:
> 
>     def range_check(int n):
>         cdef int retval = n*n
>         if retval < 0:
>             raise
> NegError('No negatives!')
>         if retval > 100:
>             raise
> ValueError('Out of range: %d' % retval)
>         return retval
> 
> 
> Note that the C compiler will likely discard the "retval
> < 0" block here. I
> assume you meant to check the input value instead?
> 

You are right, n*n < 0 would never happen.

> 
> -------------------------
> @function(str)
> @throws('n<0', ValueError, 'No nagatives: %s=%i!','desc,
> n')
> @throws('$return==NULL',
>    code="""
>     //you can also do sth else here
>     PyErr_NoMemory();
> """)
> def stringify(n=int, desc = str):
>    return """{
>    char* s = malloc(sizeof(char)*20);
>    if (s) sprintf(s, "%i", n);
>    return s;
> }"""
> -------------------------
> 
> This example will actually leak memory. Also, it won't work
> correctly on a
> 64-bit system.

First of all, thank you very much for pointing this out to me.
I'm not sure if this is something unavoidable by the
design of expy or if I can avoid this by improve
my implementation code of this particular example.
I will check this and see what I can do about it.
Meanwhile, I wonder if you can give me some suggestions,
especially on the memory leak issue.

> 
> Anyway, here's some Cython code for this:
> 
>     from stdio cimport sprintf
>     from stdlib cimport malloc, free
>     from python_exc cimport PyErr_NoMemory
> 
>     def stringify(int n, desc):
>         cdef char* s
>         if n < 0:
>              raise
> ValueError('No negatives: %s = %d' % (desc,i))
>         s = malloc(sizeof(char)*20)
>         if s is NULL:
>          
>    PyErr_NoMemory()
>         sprintf(s, "%i", n)
>         try:
>              return
> s
>         finally:
>          
>    free(s)
> 
> Personally, I'd rather write this:
> 
>     def stringify(int n, str desc):
>         if n < 0:
>              raise
> ValueError('No negatives: %s = %d' % (desc,i))
>         return str(n)
> 
> or even this:
> 
>     def stringify(unsigned int n):
>         return str(n)
> 
> which will also do the right thing.
> 

EXPY requires you to do things in pure C
when it comes to logic/functionality, the
bright side of this is that you have
full control over the implementation.
As I said, EXPY and Cython are different
in their objectives.


> 
> -------------------------
> #throws(True/False, ...):
> #special case when you provide all code
> #for exception checking and handling
> #True for arguement, False for returned values
> @function(int) #argument checking
> @throws('den > 500', MyError, "Can't handle it!")
> @throws(True, code="""
>    int i = 2;
>    while(i < den && (den % i))
> i++;
>    if (i != den){ //not a prime!
>       PyErr_SetString(PyExc_Exception,
>          "argument 'den' must
> be a prime!");
>       //usually don't return here
>       //unless no argument is of object
> type,
>       //as you need to DEC_REF it, which
>       //is automatically handled later.
>    }
> """)
> @throws(False, code="""
>    int i = 2;
>    while(i < $return && ($return
> % i)) i++;
>    if (i != $return){ //not a prime!
>       PyErr_SetString(PyExc_Exception,
>          "must return a
> prime!");
>       return NULL;
>    }
> """)
> def prime_friend(den = int):
>     return "den+2"
> -------------------------
> 
> Cython:
> 
>     cdef check_prime(int p, error_message):
>         cdef int i
>         for i in range(2, p):  #
> I'd add at least a sqrt() here
>             if not (p % i):
>            
>    raise Exception(error_message)
> 
>     def prime_friend(int den):
>         cdef int i, retval
>         if den > 500:
>             raise
> MyError("Can't handle it!")
>         check_prime(den)
>         check_prime(den+2)
>         return den+2
> 
> 
> Looking at the two implementations, I actually wonder what
> the term
> "express way" means to you exactly.
> 

Well, in EXPY, you can also define this check_prime(.) 
function and then use it, I will improve this the way 
you did. Thanks again!

Yingjie


      


More information about the capi-sig mailing list