单例为什么需要构造函数?
为什么我们不能直接创建静态方法和属性在项目中全局使用呢?如果只使用类属性而不使用对象属性,这样也不算是单例模式,对吧?这样使用会有什么问题吗?这只是像单元测试那样需要自定义构造函数的情况吗?
举个例子:
class GlobalInfo:
_global_data = {}
_lock = threading.Lock()
@staticmethod
def set_data(key, value):
with GlobalInfo._lock:
GlobalInfo._global_data[key] = value
@staticmethod
def get_data(key):
with GlobalInfo._lock:
return GlobalInfo._global_data.get(key)
我需要一些类似单例的行为,用在一个项目中,这个项目里有多个线程需要访问相同的信息。看了一些资料后,我发现大家总是重写 __new__
方法等等。我想知道我是否真的需要这样做,如果不需要的话,在我的具体情况下,我会违反单例模式吗?
1 个回答
不,在大多数情况下其实没必要这样做,你说得对。
不过在某些情况下,单例模式需要在运行时初始化——可能是为了让Python代码能使用某个配置参数的效果,或者创建其他在整个进程中都能用的资源。
在这种情况下,这些做法是有效的,但并不是必须的。
我最喜欢的一种模式是,每当我需要这样的单例时(通常我更喜欢这种方式,而不是把方法标记为静态,即使不需要初始化),就是在模块级别创建单例类的一个实例——这样这个实例就会成为在项目中被导入和使用的对象,而不是它的类。
就像这样:
class _MyConf:
def __init__(self):
# code that sets some attributes to be used process-wide
def method(self):
# plain instance method
...
MyConf = _MyConf()
接着要说明MyConf
应该被使用。
如果为了统一,想要单例能够像创建其他对象那样被调用,就像@Barmar在评论中提到的那样:
这个想法是调用者应该能够像使用其他对象一样使用单例,单例的特性只是实现细节。但你的设计要求他们以不同的方式创建实例,foo = GlobalInfo 而不是 foo = GlobalInfo()
所以——如果这是想要的,我只需在类中包含一个__call__
方法,返回self
:
class _MyConf:
def __init__(self):
# code that sets some attributes to be used process-wide
def method(self):
# plain instance method
...
def __call__(self):
return self
MyConf = _MyConf()
不过我不同意“保持可调用”的这个理由——Python自带的单例,比如None
、True
和False
都不需要“实例化”,而且它们工作得很好。不过在某些地方,这种方式可能是合适的。
需要注意的是,当涉及到静态类型时,上面的__call__
方法可能不适用——在这种情况下,使用__new__
的方法可能是个不错的选择,如果真的想让单例类在使用时假装被实例化。