3

I'm trying to define a Cython class that accepts a function as one of the class attribute in the __init__ function.

I followed this question and tried the following

ctypedef int (*f_type)(int, int)

cdef class ClassWFunction:
    cdef f_type f

    def __init__( self, f_type f):
        self.f = f

    def doStuff(self, int x, int y):
        return self.f(x, y)

cdef int example_f(int a, int b):
    return a*b

classInstance = ClassWFunction(example_f)
classInstance.doStuff(2, 4)

which gives me the error:

Cannot convert 'int (int, int)' to Python object

I also read this page from Cython's documentation and tried following that approach:

cdef class f_type:
    cpdef int evaluate(self, int a, int b) except *:
        return 0

cdef class ClassWFunctionV2:
    cdef f_type f

    def __init__( self, f_type f):
        self.f = f

    def doStuff(self, int a, int b):
        return self.f.evaluate(a, b)


cdef class example_f(f_type):
    cpdef int evaluate(self, int a, int b) except *:
        return a*b    


classInstance = ClassWFunctionV2(example_f)
classInstance.doStuff(3, 4)

which gives me a TypeError:

TypeError: Argument 'f' has incorrect type (expected _cython_magic_9f51dc40b83b28506fce9fb260a84618.f_type, got type)

Hopefully there's a way to make my first attempt work, since this second approach has a lot of boilerplate I don't quite understand! Thanks for your time...

-------- Edit ----------

The point of writing the code this way is twofold:

1) to have a flexible way to change the f function when instantiating the class. 2) The f function gets reused in many of the class methods, so I'd like to assign it to self

In my pure python code, I do stuff like

def f1(x): return x**2
def f2(x): return x**3

cl1 = ClassWFunction(f1)
cl2 = ClassWFunction(f2)

and then proceed to do things with those classes. However, I'm not 100% sure this is the best way to go around, so feel free to suggest a different approach.

-------- Edit2 ----------

As a less flexible but (hopefully!) easier alternative, I tried to hard-code the function onto the class. This would fit objective (2) above, even if it doesn't fit objective (1).

Consider (this also gives an error)

ctypedef int (*f_type)(int)
cdef class ClassWFunction:
    cdef f_type example_f
    cdef double x

    def __init__( self, int x):
        self.x = x
        # Tried with a python function too
        cdef int example_f(int z):
            return x*z
        self.example_f = example_f

    def doStuff(self, int x, int y):
        return self.example_f(x)*y

classInstance = ClassWFunction(3)
classInstance.doStuff(2, 4)
Community
  • 1
  • 1
cd98
  • 3,442
  • 2
  • 35
  • 51
  • Do you want to pass in a Python function or a C function? It's a little strange to be instantiating the class in Cython and passing a C function. Usually your extension class would be instantiated by Python code that uses it. – BrenBarn Mar 18 '15 at 02:40
  • @BrenBarn : in my code, the `example_f` is more or less critical, so I'd like to pass a cythonized function. I'd settle for passing a Python function though if the alternative is not possible. – cd98 Mar 18 '15 at 02:48
  • How do you intend to use this code in Python-space? Like, if you're just writing one static function in Cython, can't you just add it directly to the class? – BrenBarn Mar 18 '15 at 03:45
  • I added an Edit to address your question -- I hope I understood it correctly. How would you add the function directly though? – cd98 Mar 18 '15 at 04:02
  • In your original example, you pass a C function (created with `cdef`). In your edit, you pass a Python function. Are you saying you want to support both? In general `cdef` functions are only accessible from C/Cython, so if you create a `cdef` function there would be no way to pass it in using Python code. A comment on the question you linked suggests that if you want to allow passing in a Python function, you should use the `object` type. – BrenBarn Mar 18 '15 at 05:56
  • @BrenBarn : OK, I see what you mean. I added an EDIT2 above to show my attempt to hard-code a function as an attribute. If you answer with a way to solve that, I'll accept it, since maybe my original attempt is just not possible in Cython. Thanks! – cd98 Mar 18 '15 at 12:37
  • What I mean is why don't you write `example_f` as a method, just as you did with `do_stuff`? – BrenBarn Mar 18 '15 at 15:59
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/73269/discussion-between-cd98-and-brenbarn). – cd98 Mar 18 '15 at 16:01

0 Answers0