issue with singleton python call two times __init__
我有这样的单人间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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) |
当我做了几个单例时,我接到两个对init的调用,我的意思是"init"被打印了两次,而且我认为它不应该发生。
有人知道这有什么问题,或者有更好的方法来实现它??
这里有一个稍微简单的方法来写单件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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) |
尽管有更好的方法。我不得不承认我从来就不喜欢单身。我更喜欢工厂式的方法:
1 2 3 4 5 6 7 8 9 | 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年后不想要一个真正的singleton,你就不局限于一个实例。
PEP 318有一个类的单实例装饰器:
1 2 3 4 5 6 7 8 9 10 11 | def singleton(cls): instances = {} def getinstance(): if cls not in instances: instances[cls] = cls() return instances[cls] return getinstance @singleton class MyClass: ... |
(虽然我自己没用过。)
顺便说一下,关于…
I made a singleton like this
另外,您应该提到您直接从ActiveState复制了它。
因为我们都忽略了你的问题,而不是提出其他的单例实现,所以我会推荐我最喜欢的。它利用了这样一个事实:一个Python模块只加载一次,不管您导入它多少次。
它也基于python的座右铭"我们都是同意的成年人",因为如果你真的想,你可以把它实例化多次…但是你真的需要付出额外的努力去做错事。
所以在
1 2 3 4 5 6 7 8 9 10 11 12 | 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 |
然后这样使用:
1 2 3 | from mysingleton import Singleton # Use it! |
我说你必须付出额外的努力去做错事。下面是如何创建singleton类的两个实例,使其不再是singleton类:
1 | another_instance = Singleton.__class__() |
那么,如何避免这个问题呢?我引用医生的话:那就不要这样做!
注意:这是在下面的评论之后添加的
当我在这里的时候,这里有另一个单例变量,它最小化了复杂代码的数量。它使用元类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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中,您将创建这样的单例实例:
1 2 | class Singleton(metaclass=SingletonMeta): attribute ="One... two... five!" |
现在这个有点不确定了,因为singleton是一个类,您可以创建singleton的实例。从理论上讲,这是可以的,因为即使有实例,单体仍然是单体,但您需要记住,
另一种方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | >>> 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 |
如果您担心对
重写
Anyway I think using a decorator it's the best thing, because it's probably the simpler solution.
如果您想了解更多在Python中创建单例的方法,请阅读这个问题。
顺便说一下,如果您希望所有实例都具有相同的状态(而不是标识),那么您可能会对Borg模式感兴趣。如果您不确定要选择哪一个,请参阅此答案。