Paul
Paul

Reputation: 358

inheritance in Cython (short sample code)

In the following sample code, a cython class (Q) is imported. Two instances of Q are created (q1 and q2). I'd like to alter a variable inside q1 and have it affect the same variable inside q2.

Thank you very much for your time and any related information on scope or inheritance in Cython!

tc1.pyx:

cimport cython

cdef class Q:
    cdef public double q

    def __cinit__(self):
        self.q = 0

    def addone(self):
        self.q += 1

    property gsd:  # get set return
        def __get__(self):
            return self.q
        def __set__(self, value):
            pass
        def __del__(self):
            pass

.py file:

from tc1 import Q

if __name__ == "__main__":
    q1 = Q()
    q2 = Q()

    print 'q1: ', q1.gsd, 'q2: ', q2.gsd  # >> 0 and 0

    q1.addone()

    print 'q1: ', q1.gsd, 'q2: ', q2.gsd  # >> 1 and 0 (1 and 1 desired)

Upvotes: 1

Views: 821

Answers (2)

dustyrockpyle
dustyrockpyle

Reputation: 3184

Cython classes compile to C, where the class members are just values in a struct; so there's no notion of static variables for cdef classes.

You can simply declare a global pointer that Q references, however:

cimport cython
from libc.stdlib cimport malloc, free

cdef public double* global_q = <double*>malloc(sizeof(double))
global_q[0] = 0
def call_at_end():
    free(global_q)

cdef class Q:
    cdef double* q

    def __cinit__(self):
        self.q = global_q

    def addone(self):
        self.q[0] += 1

    property gsd:
        def __get__(self):
            return self.q[0]
        def __set__(self, double value):
            self.q[0] = value

Now your main function will work as expected. I added the function call_at_end to free the memory just to show how you would do it, but in this case you would never free the memory for as long as you could make an instance of Q.

Upvotes: 1

user764357
user764357

Reputation:

I'm not sure how you do it in Cython, but here is an attempt that solves it in regular Python. I'd presume if you change the propery code to use Cython decorators it should work fine.

First you need a class variable, for example _bar, then we adjust the property getter and setter methods to alter this, instead of an instance variable. The code below should illustrate this and you can verify it works on IdeOne:

class Foo(object):
    _bar = 0

    @property
    def bar(self):
        return Foo._bar

    @bar.setter
    def bar(self, value):
       Foo._bar = value

    @bar.deleter
    def bar(self):
        pass

a = Foo()
b = Foo()

print a.bar
print b.bar

a.bar += 1

print a.bar
print b.bar

This outputs the below as desired:

0
0
1
1

Upvotes: 1

Related Questions