Simple as it may seem, I've ended with two part blog post series on the subject. This part talks about decorator approach and the next part talks about classmethod approach. Enjoy.
Decorator approach
Stackoverflow hinted a decorator approach, but that example breaks Python object model. Particularly, considering:
def singleton(cls):
instances = {}
def getinstance():
if cls not in instances:
instances[cls] = cls()
return instances[cls]
return getinstance
@singleton
class MyClass(object):
pass
Then the following would reasonably fail:
c = MyClass() isinstance(c, MyClass) TypeError: isinstance() arg 2 must be a class, type, or tuple of classes and typesSince in fact after decoration
MyClass is a function and not a class.
To fix this, we'll rewrite decorator to return class instead. And to make sure that inheritance check works, we'll inherit from decorated class during decoration process.
def SingletonClass(cls):
class Single(cls):
__doc__ = cls.__doc__
_initialized = False
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(Single, cls).__new__(cls, *args, **kwargs)
return cls._instance
def __init__(self, *args, **kwargs):
if self._initialized:
return
super(Single, self).__init__(*args, **kwargs)
self.__class__._initialized = True
return Single
@SingletonClass
class MyClass(object):
pass
Now isinstance does the right thing:
>>> c = MyClass() >>> isinstance(c, MyClass) True
We are sort of double-cheating here, since even c.__class__ == MyClass is true. I say cheating because both of them are actually <class 'Single'> and original MyClass class is lost during decoration.
And a final touch is to copy a doc string of course :)
No comments:
Post a Comment