0

I am rephrasing my original question based on some of the comments (I recognized that when posted the question was not as precise as it could have been) in the hopes to find a answer.

I have the following cdef function that among various other parameters accepts an f() function defined as an ftype as shown below,

%%cython
ctypedef double (*ftype) (double)

cdef cy_myfunc(int a,..., double x, ftype f):
  ...
  cdef double result
  result = f(x)
  return result

and I define a python function such as this:

def py_myfunc(a,..., x, f):
    return cy_myfunc(a,...,x,f)

I want to be able to call py_myfunc() and pass a user python function as the f parameter (the only prerequisite of the python function is that is should accept a double and return double). Is this possible? if so how can this be achieved in cython? The f() function is used repeatedly within a loop so I would like for it to be as quick as possible.

marcos
  • 134
  • 15
  • 1
    The last sentence of your question suggests you are hoping that by using your Cython typedef but then passing a Python function as `f`, you will somehow get a speedup of the pure-Python code in `f`. That isn't going to work. If a user writes a Python function and passes it to your `cy_fmyfunc`, Cython isn't going to speed it up just because you're calling it from within a `cdef`. As suggested by deets below, you're probably better off not trying to specify any C-level type for `f`. – BrenBarn Dec 05 '18 at 22:01
  • 1
    And why the solution/link proposed in this comment to your original question https://stackoverflow.com/questions/53619438/how-to-call-a-cython-cdef-function-that-contains-as-a-parameter-a-function-in#comment94105070_53619438 doesn’t solve your problem? – ead Dec 05 '18 at 22:02
  • Basically you need jit compilation of some boilerplate code for this to work - that is what ctypes is able to do for you. – ead Dec 05 '18 at 22:05
  • @ead ctypes has nothing to do with that. It does not JIT anything. Mostly PyPy does. And some more arcane things in the scientific computing world. – deets Dec 05 '18 at 22:16
  • @deets ctypes can generate a small "JIT" function around a Python callable, which allows you to translate that callable into a C function pointer. That's impossible to do without runtime code generation. – DavidW Dec 05 '18 at 22:18
  • @marcos [this answer](https://stackoverflow.com/a/42887656/4657412) gives you a couple of other options if you're prepared to change the signature... Either way it'd be good to know why the link I gave on your other question isn't suitable – DavidW Dec 05 '18 at 22:24
  • @DavidW I find this a stretch of the term JIT. But I understand what you mean. However within this context here, this is still not helping, as all it does is moving the PyObject_Call-Semantics just one step further away. It's then not cython generating that boilerplate, it's ctypes with cython immediately delegating to it. – deets Dec 06 '18 at 12:25
  • @deets It isn't elegant or quick (or pure Cython), but it does solve the problem of turning a Python callable into a C function pointer. If the C interface is fixed then it's the only viable solution I know. If OP is able to change the C interface (e.g. to accept a PyObject* arguement) then I agree that there are better options. – DavidW Dec 06 '18 at 12:49

1 Answers1

0

I haven't tinkered with cython in a while. But conceptually your approach is flawed. By hard-coding a C-type function that can ever only be a simple pointer-value, you limited yourself too much. A python function can never be that. It will ALWAYS be represented by a Py_Object, as any callable.

Just don't declare f as a ftype, but instead a normal python object (or no type at all), and then just call it. You need the full semantics of a passed Py_Object* anyways, as cython has no way to guarantee that the passed function is not completely different callable.

deets
  • 6,285
  • 29
  • 28