user27886
user27886

Reputation: 582

How to add a static member to a Cython class (from python, not C)

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

Upvotes: 7

Views: 5322

Answers (2)

FLemaitre
FLemaitre

Reputation: 511

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.

Upvotes: 0

DavidW
DavidW

Reputation: 30889

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.

Upvotes: 6

Related Questions