how to create singleton class with arguments in python
我正在寻找创建在第一次创建时接受参数的单例类的正确方法。我的研究将我引向三种不同的方式:
Metaclass
1 2 3 4 5 6 7 8 9 | class Singleton(type): instance = None def __call__(cls, *args, **kwargs): if cls.instance is None: cls.instance = super(Singleton, cls).__call__(*args, **kwargs) return cls.instance class ASingleton(metaclass=Singleton): pass |
__new__
1 2 3 4 5 6 | class Singleton(object): instance = None def __new__(cls, *args, **kwargs): if cls.instance is None: cls.instance = super().__new__(cls, *args, **kwargs) return cls.instance |
Decorator
1 2 3 4 5 6 7 8 9 10 11 | def Singleton(myClass): instances={} def getInstance(*args, **kwargs): if myClass not in instances: instances[myClass] = myClass(*args, **kwargs) return instances[myClass] return getInstance @Singleton class SingletonTest(object): pass |
所有这些方法都可以很好地工作,但是当涉及到初始化(比如在普通类中使用uuinit_uuu)时,我无法找到正确的方法来实现它。我唯一能想到的解决方案是用这种方式使用元类方法:
1 2 3 4 5 6 7 8 9 10 11 | class Singleton(type): instance = None def __call__(cls, *args, **kwargs): if cls.instance is None: cls.instance = super(Singleton, cls).__call__(*args, **kwargs) return cls.instance class ASingleton(metaclass=Singleton): def __init__(self,j): self.j=j |
我不知道这是否是创建接受参数的singleton的正确方法。
我发现实现singleton的最佳方法是使用元类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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] # Python 2 class MyClass(): __metaclass__= Singleton # Python 3 class MyClass(metaclass=Singleton): pass |
除了@andriyivaneyko的答案,这里还有一个线程安全的元类singleton实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # Based on tornado.ioloop.IOLoop.instance() approach. # See https://github.com/facebook/tornado # Whole idea for this metaclass is taken from: https://stackoverflow.com/a/6798042/2402281 class ThreadSafeSingleton(type): _instances = {} _singleton_lock = threading.Lock() def __call__(cls, *args, **kwargs): # double-checked locking pattern (https://en.wikipedia.org/wiki/Double-checked_locking) if cls not in cls._instances: with cls._singleton_lock: if cls not in cls._instances: cls._instances[cls] = super(ThreadSafeSingleton, cls).__call__(*args, **kwargs) return cls._instances[cls] class YourImplementation(metaclass=ThreadSafeSingleton): def __init__(self, *args, **kwargs): pass # your implementation goes here |
希望你觉得它有用!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class OnlyOne: class __OnlyOne: def __init__(self, arg): self.val = arg def __str__(self): return repr(self) + self.val instance = None def __init__(self, arg): if not OnlyOne.instance: OnlyOne.instance = OnlyOne.__OnlyOne(arg) else: OnlyOne.instance.val = arg def __getattr__(self, name): return getattr(self.instance, name) |
用法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | x = OnlyOne('sausage') print(x) y = OnlyOne('eggs') print(y) z = OnlyOne('spam') print(z) print(x) print(y) print(`x`) print(`y`) print(`z`) output = ''' <__main__.__OnlyOne instance at 0076B7AC>sausage <__main__.__OnlyOne instance at 0076B7AC>eggs <__main__.__OnlyOne instance at 0076B7AC>spam <__main__.__OnlyOne instance at 0076B7AC>spam <__main__.__OnlyOne instance at 0076B7AC>spam <__main__.OnlyOne instance at 0076C54C> <__main__.OnlyOne instance at 0076DAAC> <__main__.OnlyOne instance at 0076AA3C> ''' |