3

This is how i define Singleton.

class Singleton(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]

Then I have my classes defined as:

class MyClass(object):
    __metaclass__ = Singleton

    def __init__(self):
        pass


a = MyClass()
b = MyClass()

"a is b" will return True

However,

cdef class MyCythonClass(object):
    __metaclass__ = Singleton

    def __cinit__(self):
        pass

c = MyCythonClass()
d = MyCythonClass()

"c is d" will return False

I thought it is the c code (cinit) running before init and so I tried to put the cinit back to init, it doesnt work either. The problem is solved if i removed the "cdef" before "class"

I am wondering why, probably I am missing something important here. Your help would be much appreciated.

Win 10 / Python 2.7

mcsy
  • 43
  • 6
  • not sure at all but have you tried to declare `Singleton` with `cdef` ? – Jean-François Fabre Jul 09 '18 at 12:00
  • no i didn't, this is the only way I know how to define singleton while C doesnt allow definition of keyword args ... i.e. *args , **kwargs. I am happy to have a workaround, but at the same time I am also love to understand the reason behind – mcsy Jul 09 '18 at 12:09
  • Why is it important to use a `cdef` class? Part of the point of these is that they are implemented directly in C, which lets some things work faster, but loses some of the customizability of Python. It doesn't always seem realistic to want `cdef` stuff, but then expect it to support everything Python does. (Of course, if you want to store C data-types like pointers in a singleton, that probably is reasonable...) – DavidW Jul 09 '18 at 19:46

1 Answers1

3

Cython does not appear to support meta classes out of the box. But this module may provide a workaround.

Implementing the singleton as follows may be another (safer) alternative:

cdef class Singleton:
    _instances = {}

    @classmethod
    def instance(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = cls(*args, **kwargs)
        return cls._instances[cls]

cdef class MyCythonClass(Singleton):
    pass

c = MyCythonClass.instance()
d = MyCythonClass.instance()
c is d  # True
Till Hoffmann
  • 9,479
  • 6
  • 46
  • 64
  • Thanks a lot Till! This is exactly that answer I am looking for! – mcsy Jul 10 '18 at 02:07
  • Hi Till, I just found that another problem consequent with your suggested solution, actually it is happening in my implementation...i raised a new question and put it here https://stackoverflow.com/questions/51263233/singleton-in-cython-handled-by-classmethod – mcsy Jul 10 '18 at 10:46