单例python调用两次出现问题\uuu init__
我有一个这样的单身汉单例python调用两次出现问题\uuu init__,python,singleton,init,Python,Singleton,Init,我有一个这样的单身汉 class Singleton: class __impl: def __init__(self): print "INIT" __instance = None def __init__(self): # Check whether we already have an instance if Singleton.__instance is None:
class Singleton:
class __impl:
def __init__(self):
print "INIT"
__instance = None
def __init__(self):
# Check whether we already have an instance
if Singleton.__instance is None:
Singleton.__instance = Singleton.__impl()
# Store instance reference as the only member in the handle
self.__dict__['_Singleton__instance'] = Singleton.__instance
def __getattr__(self, attr):
""" Delegate access to implementation """
return getattr(self.__instance, attr)
def __setattr__(self, attr, value):
""" Delegate access to implementation """
return setattr(self.__instance, attr, value)
当我做了几个Singleton实例时,我收到了两个调用init,我的意思是“init”被打印了两次,我认为这不应该发生
有人知道这有什么问题,或者有更好的方法来实现它???这里有一个稍微简单的方法来编写一个单例:
class Singleton(object):
__instance = None
def __new__(cls):
if cls.__instance is None:
cls.__instance = super(Singleton,cls).__new__(cls)
cls.__instance.__initialized = False
return cls.__instance
def __init__(self):
if(self.__initialized): return
self.__initialized = True
print ("INIT")
a = Singleton()
b = Singleton()
print (a is b)
尽管可能有更好的方法。我得承认我从来都不喜欢单身。我更喜欢工厂式方法:
class Foo(object):
pass
def foo_singleton_factory(_singlton = Foo()):
return _singleton
a = foo_singleton_factory()
b = foo_singleton_factory()
print (a is b)
这样做的好处是,如果您愿意,您可以继续获得相同的Foo实例,但如果您在10年后决定不想要真正的单实例,则不限于单个实例。有一个类单实例装饰器的示例:
def singleton(cls):
instances = {}
def getinstance():
if cls not in instances:
instances[cls] = cls()
return instances[cls]
return getinstance
@singleton
class MyClass:
...
(虽然我自己没用过。)
顺便说一句,关于
我做了一个这样的单身汉
class Singleton:
class __impl:
def __init__(self):
print "INIT"
__instance = None
def __init__(self):
# Check whether we already have an instance
if Singleton.__instance is None:
Singleton.__instance = Singleton.__impl()
# Store instance reference as the only member in the handle
self.__dict__['_Singleton__instance'] = Singleton.__instance
def __getattr__(self, attr):
""" Delegate access to implementation """
return getattr(self.__instance, attr)
def __setattr__(self, attr, value):
""" Delegate access to implementation """
return setattr(self.__instance, attr, value)
此外,您还应该提到您。另一种方式:
>>> class Singleton(object):
... def __new__(cls, *args, **kwargs):
... try:
... return cls._instance
... except AttributeError:
... val = cls._instance = object.__new__(cls, *args, **kwargs)
... return val
...
>>> class A(Singleton): pass
...
>>> a = A()
>>> a2 = A()
>>> a2 is a
True
>>> class B(Singleton): pass
...
>>> b = B()
>>> b2 = B()
>>> b2 is b
True
>>> b is a
False
>>> class D(Singleton):
... def __init__(self, v): self.v = v
...
>>> d = D(1)
>>> d.v
1
如果您担心对\uuuu init\uuuu
的多次调用,那么您可以选择使用装饰器还是元类
重写\uuuuu new\uuuuuu
方法允许多个\uuuuu init\uuuuuu
调用,因为如果返回的值是\uuu new\uuuuu
类的实例,python总是调用该对象的\uuuu init\uuuuu
方法
无论如何,我认为使用装饰器是最好的,因为它可能是更简单的解决方案
如果您想知道更多在python中创建单例的方法,请阅读下面的问题
顺便说一下,如果希望所有实例都具有相同的状态(而不是标识),那么您可能会对该模式感兴趣。
如果您不确定要选择哪一个,请参阅答案。因为我们都忽略了您的问题,而是建议替代的单例实现,所以我将介绍我最喜欢的。它利用了这样一个事实,即python模块只加载一次,而不管您导入它多少次 它还基于python的座右铭“我们这里都是同意的成年人”,因为如果你真的想,你可以多次实例化它。。。但是你真的需要付出额外的努力去做错事 所以在mysingleton.py中:
class SingletonClass(object):
def __init__(self):
# There's absolutely nothing special about this class
# Nothing to see here, move along
pass
# Defying PEP8 by capitalizing name
# This is to point out that this instance is a Singleton
Singleton = SingletonClass()
# Make it a little bit harder to use this module the wrong way
del SingletonClass
然后像这样使用它:
from mysingleton import Singleton
# Use it!
我说你必须付出额外的努力去做错事。以下是如何创建singleton类的两个实例,使其不再是singleton:
another_instance = Singleton.__class__()
那么如何避免这个问题呢?我要引用医生的话:那就别那么做
注意:这是在作出以下评论后添加的 当我在做这件事的时候,这里有另一个单例变体,它将复杂代码的数量降至最低。它使用元类:
class SingletonMeta(type):
# All singleton methods go in the metaclass
def a_method(cls):
return cls.attribute
# Special methods work too!
def __contains__(cls, item):
return item in cls.a_list
class Singleton(object):
__metaclass__ = SingletonMeta
attribute = "All attributes are class attributes"
# Just put initialization code directly into the class
a_list = []
for i in range(0, 100, 3):
a_list.append(i)
print Singleton.a_method()
print 3 in Singleton
在python 3中,您将创建如下的单例实例:
class Singleton(metaclass=SingletonMeta):
attribute = "One... two... five!"
现在这个有点不确定,因为singleton是一个类,您可以创建singleton的实例。理论上这是可以的,因为即使有实例,单例仍然是单例,但是您需要记住,
singleton()
不是单例--singleton
是!它甚至可以满足您的需要,使singleton属性作为类属性随时可用于其实例。您知道\uuuuuu new\uuuu()
?您似乎在做一些扭曲,以便能够将此模式插入到\uuuu init\uuuu()
。对我来说非常适合。。。你能展示一下你用来测试它的代码吗?我试过使用new,但我做不到,有太多的代码,我无法分享…你有没有机会将其子类化?我不太熟悉\uu new\uuuuuuu
中的所有魔法以及如何有效地使用它,但我的印象是,这仍然会在同一个实例上多次调用\uuuuu init\uuuu
(这是我认为OP试图避免的)Yes@mgilson您是对的。我经常使用这种方法,因为我不太关心多个init调用。我已经添加了一个关于为什么这个方法会进行多个init调用的简要说明。我喜欢这个。我唯一不喜欢的是,你真的有一个实例,你根本不能自定义实例的创建。e、 g.你不能做Singleton('foo'、'bar'、'baz')
(除非你提供\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。创建单例的最简单方法是只实例化一次类!很好,真正的单身汉。奇怪的是,在删除后,它仍然可以使用另一个类(Singleton.\uuuu class\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuo)和在SingletonClass
中定义的函数(“方法”),比如def boo(self):print'boo!'
仍然适用于另一个类的实例。沿着这些思路,b=Singleton.\uuuuu class\uuuuu()
也可以工作isinstance(b,Singleton.\uuu class\uuuuu)
(显然?)给出True
…(续b=Singleton.\uu class\uuuuu()
):b是Singleton
是False
我会添加def getinstance(*args,**kwargs):如果cls不在实例中:instances[cls]=cls(*args,**kwargs),a和b为什么是一样的?它不会给你不同的单身实例吗?@codemuncher——哪个版本?在第一个版本中,您可以看到,在第一次调用时,它设置了cls.\uu实例
,然后在后续调用中继续返回相同的cls.\uu实例
。在第二个版本中,它在创建函数时创建单例,然后继续返回该值(除非您为\u singleton
)传递不同的值)。第二个版本,对于我的下一个调用b=foo\u singleton\u factory(),它不会创建另一个对象吗,我很困惑。不,默认参数仅在创建函数时计算一次。它们不会在后续通话中重新评估。这是python中各种混乱的根源:-)。看看另一个例子,它会吸引人,但事实并非如此