8

我有一个像这样的单身人士

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”被打印了两次,我认为它不应该发生

有人知道这有什么问题或有更好的方法来实现这一点?

4

4 回答 4

17

这是编写 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 年后不再需要真正的单身人士,那么您不仅限于单个实例。

于 2012-09-06T17:32:06.323 回答
8

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 复制它

于 2012-09-06T17:32:45.120 回答
3

由于我们都忽略了您的问题,而是提出了替代的单例实现,所以我会提出我最喜欢的。它利用了一个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!"

Now this one is a little more iffy, since the singleton is a class, and you can make instances of the singleton. In theory this is OK, since the singleton will still be a singleton even if it has instances, but you need to remember that Singleton() is not the singleton -- Singleton is! It might even suit your needs to have the singleton attributes readily available to its instances as class attributes.

于 2012-09-06T17:46:59.177 回答
1

其他方式:

>>> 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 中创建单例的方法,请阅读问题。

顺便说一句,如果您想让所有实例具有相同的状态(而不是身份),那么您可能会对Borg模式感兴趣。如果您不确定选择哪一个,请参阅答案。

于 2012-09-06T17:38:41.170 回答