Python:Singleton
Method type
여기 예제중에서 call 속도도 가장 빠르고 여러가지 상속이나 기타 상황에서 가장 문제가 없는 방식이다. 사용 방식은 C/C++에서 자주사용하는 방식과 비슷하게 직접 instance 메소드를 실행하는 방법이다. 상속 순서역시 가장 뒤에 와도 상관없기 때문에 가장 좋은 방법인것 같다.
class SingletonInstane:
__instance = None
@classmethod
def __getInstance(cls):
return cls.__instance
@classmethod
def instance(cls, *args, **kargs):
cls.__instance = cls(*args, **kargs)
cls.instance = cls.__getInstance
return cls.__instance
class MyClass(BaseClass, SingletonInstane):
pass
c = MyClass.instance()
A decorator
빠르지만 클래스 자체를 호출할경우 함수가 리턴되기 때문에 클래스의 StaticMethod에 접근할수가 없다..
def singleton(class_):
instances = {}
def getinstance(*args, **kwargs):
if class_ not in instances:
instances[class_] = class_(*args, **kwargs)
return instances[class_]
return getinstance
@singleton
class MyClass(BaseClass):
pass
A base class
데코레이터 타입의 싱글톤보다 아주 살짝 느리지만 일반적인 클래스처럼 쓸 수가 있기 때문에 가장 범용적이다.
class Singleton(object):
_instance = None
def __new__(class_, *args, **kwargs):
if not isinstance(class_._instance, class_):
class_._instance = object.__new__(class_, *args, **kwargs)
return class_._instance
class MyClass(Singleton, BaseClass):
pass
A metaclass
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]
#Python2
class MyClass(BaseClass):
__metaclass__ = Singleton
#Python3
class MyClass(BaseClass, metaclass=Singleton):
pass
Decorator returning a class with the same name
데코레이터로 사용하며, 클래스명(__name__
속성)을 덮어쓰고, object.__new__(cls)
오류를 해결한 버전:
# -*- coding: utf-8 -*-
from inspect import signature
def singleton(base):
class _Wrapper(base):
__singleton_instance__ = None
def __new__(cls, *args, **kwargs):
if _Wrapper.__singleton_instance__ is None:
super_cls = super(_Wrapper, cls)
if object.__new__ == super_cls.__new__:
instance = super_cls.__new__(cls)
else:
new_sig = signature(super_cls.__new__)
ba = new_sig.bind(cls, *args, **kwargs)
ba.apply_defaults()
instance = super_cls.__new__(*ba.args, **ba.kwargs)
_Wrapper.__singleton_instance__ = instance
_Wrapper.__singleton_instance__.__singleton_sealed__ = False
return _Wrapper.__singleton_instance__
def __init__(self, *args, **kwargs):
if self.__singleton_sealed__:
return
super(_Wrapper, self).__init__(*args, **kwargs)
self.__singleton_sealed__ = True
@staticmethod
def get_singleton_instance() -> base:
return _Wrapper.__singleton_instance__
_Wrapper.__name__ = base.__name__
return _Wrapper
유닛 테스트:
# -*- coding: utf-8 -*-
from unittest import TestCase, main
from cw.patterns.singleton import singleton
@singleton
class _TestNoInheritance:
def __init__(self, value=999):
self.value = value
@classmethod
def name(cls):
return cls.__name__
class _TestBase:
def __new__(cls, value=888):
return object.__new__(cls)
def __init__(self, value=999):
self.value = value
@classmethod
def name(cls):
return cls.__name__
@singleton
class _TestInheritance(_TestBase):
def __init__(self, value=999):
super().__init__(value)
@classmethod
def name(cls):
return cls.__name__
class SingletonTestCase(TestCase):
def test_no_inheritance(self):
o0 = _TestNoInheritance(100)
o1 = _TestNoInheritance(200)
o2 = _TestNoInheritance(300)
o3 = _TestNoInheritance()
self.assertTrue(hasattr(o0, "__singleton_instance__"))
self.assertTrue(hasattr(o1, "__singleton_instance__"))
self.assertTrue(hasattr(o2, "__singleton_instance__"))
self.assertTrue(hasattr(o3, "__singleton_instance__"))
self.assertIsNotNone(getattr(o0, "__singleton_instance__"))
self.assertIsNotNone(getattr(o1, "__singleton_instance__"))
self.assertIsNotNone(getattr(o2, "__singleton_instance__"))
self.assertIsNotNone(getattr(o3, "__singleton_instance__"))
self.assertTrue(hasattr(o0, "__singleton_sealed__"))
self.assertTrue(hasattr(o1, "__singleton_sealed__"))
self.assertTrue(hasattr(o2, "__singleton_sealed__"))
self.assertTrue(hasattr(o3, "__singleton_sealed__"))
self.assertEqual(o0.value, 100)
self.assertEqual(o1.value, 100)
self.assertEqual(o2.value, 100)
self.assertEqual(o3.value, 100)
self.assertEqual(o0.name(), "_TestNoInheritance")
self.assertEqual(o1.name(), "_TestNoInheritance")
self.assertEqual(o2.name(), "_TestNoInheritance")
self.assertEqual(o3.name(), "_TestNoInheritance")
self.assertEqual(id(o0), id(o1))
self.assertEqual(id(o0), id(o2))
self.assertEqual(id(o0), id(o3))
def test_inheritance(self):
o0 = _TestInheritance(100)
o1 = _TestInheritance(200)
o2 = _TestInheritance(300)
o3 = _TestInheritance()
self.assertTrue(hasattr(o0, "__singleton_instance__"))
self.assertTrue(hasattr(o1, "__singleton_instance__"))
self.assertTrue(hasattr(o2, "__singleton_instance__"))
self.assertTrue(hasattr(o3, "__singleton_instance__"))
self.assertIsNotNone(getattr(o0, "__singleton_instance__"))
self.assertIsNotNone(getattr(o1, "__singleton_instance__"))
self.assertIsNotNone(getattr(o2, "__singleton_instance__"))
self.assertIsNotNone(getattr(o3, "__singleton_instance__"))
self.assertTrue(hasattr(o0, "__singleton_sealed__"))
self.assertTrue(hasattr(o1, "__singleton_sealed__"))
self.assertTrue(hasattr(o2, "__singleton_sealed__"))
self.assertTrue(hasattr(o3, "__singleton_sealed__"))
self.assertEqual(o0.value, 100)
self.assertEqual(o1.value, 100)
self.assertEqual(o2.value, 100)
self.assertEqual(o3.value, 100)
self.assertEqual(o0.name(), "_TestInheritance")
self.assertEqual(o1.name(), "_TestInheritance")
self.assertEqual(o2.name(), "_TestInheritance")
self.assertEqual(o3.name(), "_TestInheritance")
self.assertEqual(id(o0), id(o1))
self.assertEqual(id(o0), id(o2))
self.assertEqual(id(o0), id(o3))
if __name__ == "__main__":
main()