masouduut94
masouduut94

Reputation: 1122

Cython - trying to modify function in subclass which is already declared in superclass , but error occurs

I coded these four classes in jupyter-notebook. first two classes are in python and the other two classes with similar operations are in cython:

%load_ext cython

%%cython

# py_child inherits from py_parent
class py_parent:
    def __init__(self, var1, var2):
        self.var1 = var1
        self.var2 = var2

    def func1(self):
        return self.var1 + self.var2

    def func2(self):
        return self.var1 * self.var2

    class py_child(py_parent):
        def func1(self, inp):
            return self.var1 + self.var2, self.var1 + inp, self.var2 + inp

# In the next cell I coded these modules
# cy_child inherits from cy_parent

cdef class cy_parent:
    cdef public:
        int var1, var2
    def __init__(self, var1, var2):
        self.var1 = var1
        self.var2 = var2

    cpdef int func1(self):
        return self.var1 + self.var2

    cpdef int func2(self):
        return self.var1 * self.var2

cdef class cy_child(cy_parent):
    def __init__(self, var1, var2):
        super().__init__(var1, var2)

    cpdef tuple func1(self, int inp):
        return self.var1 + self.var2, self.var1 + inp, self.var2 + inp

I run code below for python classes and it works just fine:

a = py_child(1,1)
print(a.func1(2)) 

But for cy_child and cy_parent I get this error:

cpdef tuple func1(self, int inp):
     ^
------------------------------------------------------------

Signature not compatible with previous declaration

I also get this error after that: Call with wrong number of arguments (expected 1, got 2)

Why this error happens for cython classes but not python classes.
Assume that I want the superclass cy_parent keep the func1 function unchanged and want to modify its subclass cy_child.func1 function in the way I showed. How can I fix the error then? Any suggestion would be highly appreciated.

Upvotes: 1

Views: 819

Answers (1)

DavidW
DavidW

Reputation: 30917

This will "work" if you change cpdef to def, but what you're doing makes no sense.

Inheritance usually indicates a "is a" relationship - i.e. cy_child is a cy_parent and should be able to do everything a cy_parent can do, (and possibly some other stuff). Therefore, it can be used in your code anywhere that you can use a cy_parent. By trying to change the function signature you're making it so that it can do longer do the same things and so breaking that rule.

With a cpdef function your asking Cython to generate code so that the following code generates a fast C function call to the correct function whether it's passed a cy_parent or cy_child:

def example(cy_parent x):
  x.func1()

Since the functions take different numbers of arguments it is not possible to do this and hence Cython (rightly) complains. With pure Python code you put the problem off until you run the code, but the problem still exists (you'll get an exception about the wrong number of arguments).

There's two "solutions":

  1. you shouldn't be using inheritance since it doesn't represent the model you're trying to code.
  2. If you're just trying to add extra functionality onto cy_child then you should give the new function a different name (since it's doing something different). This represents a case where you still want to be able to use cy_parent's func1 with cy_child but you also want the option of doing a similar action with an extra argument.

Upvotes: 1

Related Questions