6

How would I add a static, typed member to a cython class? The syntax for adding typed instance-members uses the syntax as follows (e.g.):

import cython

cdef class NoStaticMembers:

   cdef public int instanceValue # but, how do I create a static member??

   def __init__(self, int value):
       self.instanceValue = value
user27886
  • 540
  • 12
  • 27
  • possibly related: http://stackoverflow.com/questions/28749209/do-cython-extension-types-support-class-attributes/28770515#28770515 – cel Mar 13 '15 at 06:35
  • @cel that is related but it doesn't appear they solved it either. – user27886 Mar 13 '15 at 07:04
  • You seem to assume that this must be possible. I am not so sure about that. – cel Mar 13 '15 at 07:09
  • it compiles to C, it must be. C has static class members. – user27886 Mar 13 '15 at 07:14
  • You cannot make that conclusion. Cython code is translated to C, but to make that conclusion you assume that every valid c program is also valid cython code. And it's pretty obvious that this is not the case. – cel Mar 13 '15 at 10:37
  • 2
    Also, `C` is not object-oriented, so what exactly is a `static class member` in `C`? – cel Mar 13 '15 at 11:13
  • @cel when I said 'it has to be' I meant that it is an obvious feature that could be implemented in cython based on C++... Possibly I'll have to add the ugly hack myself to the translated C code to get it to work, but that seems to be. Also Yes, I was confusing C and C++. You're right C structs have no static members. – user27886 Mar 13 '15 at 16:03

2 Answers2

4

Just because you can do it in C really doesn't mean you can do it in Cython.

A workround might involve using global variables, and class properties so you can access them through class instances. I'm not sure if it's really better than using global variables though

import cython

cdef int MyClass_static_variable

cdef class MyClass:
   property static_variable:
      def __get__(self):
         return MyClass_static_variable

      def __set__(self, x):
         global MyClass_static_variable
         MyClass_static_variable = x

You'd have to measure how much speed you lost through that method (and maybe consider making __get__ and __set__ cpdef if you can - I'm not sure). The only thing that doesn't let you do that a genuine static variable does is to access it as MyClass.static_variable.

DavidW
  • 29,336
  • 6
  • 55
  • 86
0

Another workaround (with a nested class, which is a specific kind of class attribute):

from cpython.object cimport PyTypeObject, PyObject
from cpython.dict cimport PyDict_SetItem

cdef class Test1:
    pass

cdef class Test2:
    pass

# Building something close to:
#
# class Test1:
#     class Test2:
#         pass

PyDict_SetItem(<object>(<PyTypeObject*>Test1).tp_dict, 'Test2', Test2)
del globals()['Test2'] 

Which seems to work (the exception is expected):

>>> import mymodule
>>> mymodule.Test1
<class 'mymodule.Test1'>
>>> mymodule.Test2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module 'mymodule' has no attribute 'Test2'
>>> mymodule.Test1.Test2
<class 'mymodule.Test2'>

I'm using a nested class here, but it could be anything.

It's not 100% clean:

  • I would have expected <class 'mymodule.Test1.Test2'> as a result to my last query (could be fixed, but do we want more tricks?)
  • Modifying tp_dict after PyType_Ready is not clean (is it?). But, in our specific use case, I think it doesn't matter.
FLemaitre
  • 503
  • 2
  • 9