Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
679 views
in Technique[技术] by (71.8m points)

python - Function pointer in cython extension type

I am writing a cython module that provides several extension types that use optimized cdef functions. Several of these extension types (about 10, each containing about 200 lines of code) have exactly the same structure but don't call the same cdef functions. I would like to factorize my module so that only one extension type can handle all the different configurations I need.

To make this clearer, here is a (very silly) example of the structure of the module I'm writing :

cdef class A1:

    cdef double x

    def __init__(self, double x):
        self.x = x

    def apply(self):
        self.x = f1(self.x)

cdef class A2:

    cdef double x

    def __init__(self, double x):            
        self.x = x

    def apply(self):
        self.x = f2(self.x)       

cdef double f1(double x):
    return x**1

cdef double f2(double x):
    return x**2

...

and the kind of factorized code I would like to obtain :

cdef class A:

    cdef int n
    cdef double x

    def __init__(self, double x, int n):
        self.x = x
        self.f = globals()[f'f{n}']

    def apply(self):
        self.x = self.f(self.x)

In pure Python, this kind of structure is easy to setup using globals or getattr, but in cython cdef objects are (of course) not accessible from python, so not in globals().

I guess that a C implementation of this kind of code would use function pointers but I can't find how to do this inside an cython extension type. Actually the real question is 'is it possible to add a pointer to a cdef function as an instance attribute (in self) ? If not, how can I factorize this kind of code without losing performances (i.e. without changing my cdef functions) ?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You could use function pointer, but with a little bit more boilerplate code than in pure python, for example:

%%cython

# here all possible functions double->double
cdef double fun1(double x):
    return 2*x

cdef double fun2(double x):
    return x*x;
...

# class A wraps functions of type double->double
ctypedef double(*f_type)(double) 

# boiler-plate code for obtaining the right functor
# uses NULL to signalize an error
cdef f_type functor_from_name(fun_name) except NULL:
    if fun_name == "double":
        return fun1
    elif fun_name == "square":
        return fun2
    else:
        raise Exception("unknown function name '{0}'".format(fun_name)) 


cdef class A:
    cdef f_type fun

    def __init__(self, fun_name ):
        self.fun = functor_from_name(fun_name)

    def apply(self, double x):
        return self.fun(x)

I'm not aware of a possibility to get cdef-function pointer from the name of the function at run time and I don't think there is one out-of-the-box.

And now it works as advertised:

>>> doubler = A("double")
>>> double.apply(3.0)
6.0
>>> squarer = A("square")
>>> squarer.apply(3.0)
9.0
>>> dummy = A("unknown")
Exception: unknown function name 'unknown'

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...