在Python中似乎有很多方法来定义单例对象。对Stack Overflow是否有一致的意见?


当前回答

你可以像这样重写__new__方法:

class Singleton(object):
    _instance = None
    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(
                                cls, *args, **kwargs)
        return cls._instance


if __name__ == '__main__':
    s1 = Singleton()
    s2 = Singleton()
    if (id(s1) == id(s2)):
        print "Same"
    else:
        print "Different"

其他回答

模块方法工作得很好。如果我绝对需要一个单例,我更喜欢元类方法。

class Singleton(type):
    def __init__(cls, name, bases, dict):
        super(Singleton, cls).__init__(name, bases, dict)
        cls.instance = None 

    def __call__(cls,*args,**kw):
        if cls.instance is None:
            cls.instance = super(Singleton, cls).__call__(*args, **kw)
        return cls.instance

class MyClass(object):
    __metaclass__ = Singleton

我认为强制一个类或实例为单例是多余的。就我个人而言,我喜欢定义一个普通的可实例化类、一个半私有引用和一个简单的工厂函数。

class NothingSpecial:
    pass

_the_one_and_only = None

def TheOneAndOnly():
    global _the_one_and_only
    if not _the_one_and_only:
        _the_one_and_only = NothingSpecial()
    return _the_one_and_only

或者如果在模块第一次导入时实例化没有问题:

class NothingSpecial:
    pass

THE_ONE_AND_ONLY = NothingSpecial()

通过这种方式,您可以针对新的实例编写测试,而不会产生副作用,并且不需要在模块中添加全局语句,如果需要,您可以在将来派生变体。

辛格尔顿同父异母的兄弟

我完全同意staale的观点,我在这里留下了一个创建单胎同父异母兄弟的例子:

class void:pass
a = void();
a.__class__ = Singleton

即使看起来不像单例,A现在也会报告为与单例属于同一个类。因此,使用复杂类的单例最终依赖于我们没有过多地干扰它们。

因此,我们可以使用更简单的东西,如变量或模块,以达到同样的效果。尽管如此,如果我们想要使用类来明确,并且因为在Python中类是一个对象,所以我们已经有了对象(不是实例,但它会像)。

class Singleton:
    def __new__(cls): raise AssertionError # Singletons can't have instances

如果我们尝试创建一个实例,我们会有一个很好的断言错误,我们可以在派生上存储静态成员,并在运行时对它们进行更改(我喜欢Python)。这个对象和其他同父异母的兄弟一样好(如果你愿意,你仍然可以创建它们),但是由于简单,它往往会运行得更快。

好吧,我知道,单胞胎可能是好的,也可能是坏的。这是我的实现,我只是扩展了一个经典的方法,在里面引入一个缓存,并产生许多不同类型的实例,或者许多相同类型的实例,但具有不同的参数。

我称它为Singleton_group,因为它将相似的实例分组在一起,并防止创建具有相同参数的相同类的对象:

# Peppelinux's cached singleton
class Singleton_group(object):
    __instances_args_dict = {}
    def __new__(cls, *args, **kwargs):
        if not cls.__instances_args_dict.get((cls.__name__, args, str(kwargs))):
            cls.__instances_args_dict[(cls.__name__, args, str(kwargs))] = super(Singleton_group, cls).__new__(cls, *args, **kwargs)
        return cls.__instances_args_dict.get((cls.__name__, args, str(kwargs)))


# It's a dummy real world use example:
class test(Singleton_group):
    def __init__(self, salute):
        self.salute = salute

a = test('bye')
b = test('hi')
c = test('bye')
d = test('hi')
e = test('goodbye')
f = test('goodbye')

id(a)
3070148780L

id(b)
3070148908L

id(c)
3070148780L

b == d
True


b._Singleton_group__instances_args_dict

{('test', ('bye',), '{}'): <__main__.test object at 0xb6fec0ac>,
 ('test', ('goodbye',), '{}'): <__main__.test object at 0xb6fec32c>,
 ('test', ('hi',), '{}'): <__main__.test object at 0xb6fec12c>}

每个对象都携带单例缓存…这可能是邪恶的,但对一些人来说很有用:)

正如公认的答案所说,最常用的方法是只使用一个模块。

考虑到这一点,下面是一个概念的证明:

def singleton(cls):
    obj = cls()
    # Always return the same object
    cls.__new__ = staticmethod(lambda cls: obj)
    # Disable __init__
    try:
        del cls.__init__
    except AttributeError:
        pass
    return cls

有关__new__的更多详细信息,请参阅Python数据模型。

例子:

@singleton
class Duck(object):
    pass

if Duck() is Duck():
    print "It works!"
else:
    print "It doesn't work!"

注:

为此,您必须使用new-style类(派生自object)。 单例在定义时初始化,而不是在第一次使用时初始化。 这只是一个简单的例子。我从未在产品代码中实际使用过它,也不打算这样做。