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


当前回答

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

我称它为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>}

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

其他回答

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

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()

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

作为Python的新手,我不确定最常见的习语是什么,但我能想到的最简单的事情就是使用模块而不是类。类中的实例方法变成了模块中的函数,任何数据都变成了模块中的变量,而不是类的成员。我怀疑这是解决人们使用单例对象的问题的python方法。

如果你真的想要一个单例类,有一个合理的实现描述在谷歌的第一个点击“Python singleton”,具体地说:

class Singleton:
    __single = None
    def __init__( self ):
        if Singleton.__single:
            raise Singleton.__single
        Singleton.__single = self

这似乎奏效了。

请看来自PEP318的实现,使用装饰器实现单例模式:

def singleton(cls):
    instances = {}
    def getinstance():
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return getinstance

@singleton
class MyClass:
    ...

谷歌Testing博客上也有一些有趣的文章,讨论了为什么单例是/可能是不好的,并且是一种反模式:

单身人士是病态的说谎者 单身人士都去哪儿了? 单身的根本原因

如果你想继续装饰(注释)类,创建一个单例装饰器(又名注释)是一种优雅的方式。然后将@singleton放在类定义之前。

def singleton(cls):
    instances = {}
    def getinstance():
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return getinstance

@singleton
class MyClass:
    ...