我有一个这样的单身人士
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(_singleton= Foo()):
return _singleton
a = foo_singleton_factory()
b = foo_singleton_factory()
print (a is b)
这样做的好处是,如果您愿意,您可以继续获得相同的 Foo 实例,但如果您决定 10 年后您不想要真正的单例,则不受限于单个实例。
PEP 318 有一个类的单例装饰器示例:
def singleton(cls):
instances = {}
def getinstance():
if cls not in instances:
instances[cls] = cls()
return instances[cls]
return getinstance
@singleton
class MyClass:
...
(虽然我自己没用过。)
顺便说一句,关于...
我做了一个这样的单例
此外,您应该提到您直接从 ActiveState 复制它。
它也基于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
是!它甚至可能满足您的需要,让单例属性可以作为类属性供其实例使用。
class Singleton(object):
def __new__(cls, *args, **kwargs):
try:
return cls._instance
except AttributeError:
val = cls._instance = object.__new__(cls)
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答案。