我正在尝试实现这里找到的Borg设计模式(在下面重新创建):http://python-3-patterns-idioms-test.readthedocs.io/en/latest/Singleton.html。
class Borg:
_shared_state = {}
def __init__(self):
self.__dict__ = self._shared_state
class Singleton(Borg):
def __init__(self, arg):
Borg.__init__(self)
self.val = arg
def __str__(self): return self.val我想在这个类的第一个初始化时运行一个特定的方法,但是再也不运行了。最初,我尝试使用一些布尔标志,但据我所知,Singleton类被多次初始化,但是状态和行为在所有实例中都是常见的。因此,我在init方法中进行的任何初始化都不止一次,因此每次初始化Singleton方法时都会重置标志。
我找到了一种可行的解决方案,但我想知道是什么最能做到这一点,因为我不相信这就是它。我做了以下工作:
class Singleton(Borg):
def __init__(self, arg):
Borg.__init__(self)
if not self.__dict__: #I'm just checking that the namespace is empty, knowing it will be filled with something in the future.
firstInitializationMethod()任何帮助都是非常感谢的,如果需要更多的细节,请告诉我。我是新来的。谢谢!
发布于 2016-07-08 01:29:03
我认为您的解决方案并没有那么糟糕,因为您必须先填充__dict__,然后才能再次调用init,否则将不止一次地调用firstInitializationMethod()。这在您的示例中肯定会发生,因为有了self.val = arg。
但是,如果您的Simpleton在其__init__调用中不执行类实例命名空间中的赋值,那么您的解决方案可能会失败。
更简单和健壮的方法就是使用类属性,如下所示:
class Singleton(Borg):
_first_initialization = True
def __init__(self,arg):
Borg.__init__(self)
if Singleton._first_initialization:
firstInitializationMethod()
Singleton._first_initialization = False您可以通过使用print替换firstInitializationMethod()并创建一些Simpleton对象来测试这段代码,以确保它只被调用一次。
这是可行的,而且_first_initialization不会在每个__init__调用中被重写回True,因为类名称空间是,将与类实例命名空间分离,而Borg只会影响后者(即使Simpleton的所有实例使用相同的__dict__)。
后续问题:--我尝试了用self代替Singleton的代码,但它仍然有效。他们似乎决心要做同样的事情。有理由使用Singleton吗?
考虑使用以下两种方法的代码,其中SingletonSelfless是使用Singleton._first_initialization的,tinker()只是返回self.__first_initialization
a = Singleton('a')
print(a)
b = Singleton('b')
print(a,b)
c = Singleton('c')
print(a,b,c)
print(Singleton._first_initialization, a.tinker(),b.tinker(),c.tinker())
a = SingletonSelfless('a')
print(a)
b = SingletonSelfless('b')
print(a,b)
c = SingletonSelfless('c')
print(a,b,c)
print(SingletonSelfless._first_initialization, a.tinker(),b.tinker(),c.tinker())及其产出:
doing some init!!
a
b b
c c c
True False False False
doing some init!!
a
b b
c c c
False False False False从实际的角度来看,这两种实现都像我们希望的那样工作,但是与_first_initialization变量的值有明显的区别。
答案很简单。即使类名称空间和类实例命名空间是分开的,实例仍然可以访问类命名空间。但是它只是作为回退类-类实例命名空间具有绝对优先级-但是当它在自己的实例名称中找不到名称时,它就尝试使用类1。让我们来看看__init__在这个Singleton中
class Singleton(Borg):
_first_initialization = True
def __init__(self,arg):
Borg.__init__(self)
if self._first_initialization:
print('doing some init!!')
self._first_initialization = False
self.val = arg
def tinker(self):
return self._first_initialization
def __str__(self): return self.val尽管实例没有_first_initialization,但我们的if正在使用Singleton._first_initialization进行解析。但是,将self._first_initialization设置为False将在实例命名空间中创建_first_initialization变量。谢谢Borg,我们的所有实例都共享相同的__dict__,因此在以后的init调用中,类实例名称空间中将有一个_first_initialization (在第一次__init__调用时使用值False创建的名称空间),并且我们的条件语句将按我们希望的那样解析--而不是执行另一个firstInitializationMethod() (这里是用于演示查询的打印)。
但是,驻留在类命名空间中的原始_first_initialization保持不变。这就是我们得到True False False False的原因。
在SingletonSelfless中,我们从不在类实例中创建_first_initialization,所以tinker()调用将回到类命名空间。这就是为什么有4个错误-所有调用指向同一个对象(SingletonSelfless._first_initialization bool变量)。
在Singleton中,我们有两个不同的对象--一个来自类命名空间,另一个来自类实例名称空间,在实例之间共享。那么,为什么使用Singleton.而不是self.呢?好吧,对于第一个开始,我们“节省”了难以置信的小内存,在那里只有一个_first_initialization的bool!但真正的原因是很难意外地更改隐藏在类命名空间中的变量。如果我们正在使用self._first_initialization,并且在代码的后面某个地方发生了类似的事情--无论出于什么原因(或者Borg的_shared_dict将被清除或更改,会影响驻留在其中的_shared_dict):a._first_initialization = 'Lol'、Singleton或其子方法self._first_initialization = 'ROFL',那么我们在处理新的Singleton对象时会遇到一些严重的问题。对于Singleton._first_initialization,它会很好,因为init使用的变量只能由显式Singleton._first_initialization='bad idea'修改
发布于 2018-05-24 10:20:38
我知道这很古老,但我只是想到了以下解决方案:
class Borg(object):
_state = {}
def __new__(cls, hive_name, *p):
self = object.__new__(cls, *p)
if hive_name not in cls._state:
cls._state[hive_name]={}
self.__dict__ = cls._state[hive_name]
self.__init_hive__(*p)
else:
self.__dict__ = cls._state[hive_name]
return self
def __init_hive__(self, *p):
pass这个实现允许您创建多个共享状态(为了与主题保持一致,我调用了这些单元)并自由地分配实例。当创建一个单元格时,它调用单元中第一个实例上的__init_hive__方法,传递实例化参数。例如
class WeAre(Borg):
def __init__(self, hive_name, arg):
super(WeAre, self).__init__(hive_name, arg)
def __init_hive__(self, arg):
self.hive_arg=arg
# Prints foo
print WeAre("The Collective", "foo").hive_arg
# Prints foo again
print WeAre("The Collective", "bar").hive_arg
# Prints bar
print WeAre("The Hive", "bar").hive_arghttps://stackoverflow.com/questions/38256609
复制相似问题