我有一个像这样的单身人士
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”被打印了两次,我认为它不应该发生
有人知道这有什么问题,或者有更好的方法来实现这个?
答案 0 :(得分:8)
这是编写Singleton的一种稍微简单的方法:
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年后不想要一个真正的单身人士,那么你不仅限于一个实例。
答案 1 :(得分:6)
PEP 318有一个类的单例装饰器示例:
def singleton(cls):
instances = {}
def getinstance():
if cls not in instances:
instances[cls] = cls()
return instances[cls]
return getinstance
@singleton
class MyClass:
...
(虽然我自己没有用过它。)
是的,关于......我做了像这样的单身人士
另外,你应该提到你copied it directly from ActiveState。
答案 2 :(得分:2)
由于我们都忽略了你的问题,而是提出了替代单例实现,我将与我最喜欢的人交往。它利用了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!
我说你必须付出额外的努力才能做错事。以下是如何创建单例类的两个实例,使其不再是单例:
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
是!它甚至可能满足您的需要,让单例属性可以作为类属性随时可用于其实例。
答案 3 :(得分:0)
另一种方式:
>>> 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
如果您担心多次调用__init__
,则可以选择使用装饰器还是元类。
覆盖__new__
方法允许多个__init__
调用,因为如果返回的值是该类的实例,则python始终调用__init__
返回的对象的__new__
方法
无论如何,我认为使用装饰器是最好的,因为它可能是更简单的解决方案。
如果您想了解更多在python中创建单例的方法,请阅读this问题。
顺便说一句,如果你想让所有实例具有相同的状态(而不是身份),那么你可能会对Borg模式感兴趣。 如果您不确定选择哪一个,请参阅this answer。