MaMiFreak
MaMiFreak

Reputation: 789

Cython, using function pointer inside class

I am trying to use a pointer inside a cython class.

the outside_class ctypedef works like a charm but i am unable to get the inside_class to work. a "ctypedef statement not allowed here" error is thrown and i don't understand what is wrong.

Why should this work
the outside_class typdef works so i assumed it should also work inside. I was unable to get it to work so i tried to find some more information on it, unfortunately all information is about the outside_class example so i do not know whether the other is allowed or even possible. to me it seems the only difference is the self argument.

Why do i want this to work
This class is going to contain 35+ functions with the same arguments, when used only a part of those functions is called in a specific order. When initializing i want to create an array with all functions in the correct order. Of course a different way of doing so is also welcome.

updated code sample 14-02

test A & B work but C & D do not, error message is given below.

My code:

ctypedef int (*outside_class)()
ctypedef int (*inside_class)(Preprocess)

cdef int outside_foo():
    return 12

cdef int outside_bar(Preprocess self):
    return 20

cdef class Preprocess:

    cdef int inside_foo(self):
        return 18

    cdef int inside_bar(self):
        return 14

    cdef int inside_sek(self):
        return 16

    def __init__(self):

        cdef outside_class test_A
        test_A = &outside_foo
        print( test_A() )

        cdef inside_class test_B
        test_B = &outside_bar
        print( test_B(self) )

        cdef inside_class test_C
        test_C = &self.inside_foo
        #print( test_C(self) )

        print( "no error, yet.." )

        cdef inside_class test_D
        test_D = &self.inside_foo
        print( test_D(self) )

error

/home/boss/.pyxbld/temp.linux-x86_64-2.7/pyrex/aa/preprocessing/preprocessing.c: In function ‘__pyx_pf_7aa_13preprocessing_13preprocessing_10Preprocess___init__’:
/home/boss/.pyxbld/temp.linux-x86_64-2.7/pyrex/aa/preprocessing/preprocessing.c:938:18: warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
   __pyx_v_test_C = (&((struct __pyx_vtabstruct_7aa_13preprocessing_13preprocessing_Preprocess *)__pyx_v_se
                  ^
/home/boss/.pyxbld/temp.linux-x86_64-2.7/pyrex/aa/preprocessing/preprocessing.c:955:18: warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
   __pyx_v_test_D = (&((struct __pyx_vtabstruct_7aa_13preprocessing_13preprocessing_Preprocess *)__pyx_v_se
                  ^
12
20
no error, yet..
Segmentation fault (core dumped)

Upvotes: 0

Views: 1054

Answers (1)

hpaulj
hpaulj

Reputation: 231385

cython raises the error as soon as it sees the cdeftype within the class definition. It hasn't even looked at, or run, the &self.inside_foo assignment:

0000:~/mypy/cython3$ cython stack42214943.pyx -a

Error compiling Cython file:
------------------------------------------------------------
...
cdef int outside_foo():
    return 12

cdef class Preprocess:

    ctypedef int (*inside_class)(Preprocess)
   ^
------------------------------------------------------------

stack42214943.pyx:8:4: ctypedef statement not allowed here

If I try cdef int(*)(Preprocess) inside_test, I get a Syntax error in C variable declaration. Again before the self line.


(edit)

With the following code I can create and run both a python list of 3 functions and a C array of the same.

def __init__(self):
    cdef outside_class test_A
    test_A = &outside_foo
    print( test_A() )

    cdef inside_class test_B
    test_B = &outside_bar
    print( test_B(self) )
    print(self.inside_foo())

cpdef evalc(self):
    # cdef int (*inside_array[3]) (Preprocess)
    cdef inside_class inside_array[3]
    inside_array[0] = self.inside_foo
    inside_array[1] = self.inside_bar
    inside_array[2] = self.inside_sek

    print('eval inside_array')
    for fn in inside_array:
        print(fn(self))

def evals(self):
    alist = [self.inside_foo, self.inside_bar, self.inside_sek]
    alist = [fn(self) for fn in alist]
    print(alist)
    self.evalc()

In an Ipython session I can compile and import this, and run it with:

In [3]: p=stack42214943.Preprocess()
12
20
18

In [4]: p.evals()
[18, 14, 16]
eval inside_array
18
14
16

In [5]: p.evalc()
eval inside_array
18
14
16

I haven't figured out how to define and access inside_array outside of the evalc function. But maybe I don't need to. And instead of printing, that function could return the 3 values as some sort of int array or list.

Upvotes: 1

Related Questions