singleton python调用有两次__init__问题

issue with singleton python call two times __init__

我有这样的单人间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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)

当我做了几个单例时,我接到两个对init的调用,我的意思是"init"被打印了两次,而且我认为它不应该发生。

有人知道这有什么问题,或者有更好的方法来实现它??


这里有一个稍微简单的方法来写单件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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)

尽管有更好的方法。我不得不承认我从来就不喜欢单身。我更喜欢工厂式的方法:

1
2
3
4
5
6
7
8
9
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年后不想要一个真正的singleton,你就不局限于一个实例。


PEP 318有一个类的单实例装饰器:

1
2
3
4
5
6
7
8
9
10
11
def singleton(cls):
    instances = {}
    def getinstance():
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return getinstance

@singleton
class MyClass:
    ...

(虽然我自己没用过。)

顺便说一下,关于…

I made a singleton like this

另外,您应该提到您直接从ActiveState复制了它。


因为我们都忽略了你的问题,而不是提出其他的单例实现,所以我会推荐我最喜欢的。它利用了这样一个事实:一个Python模块只加载一次,不管您导入它多少次。

它也基于python的座右铭"我们都是同意的成年人",因为如果你真的想,你可以把它实例化多次…但是你真的需要付出额外的努力去做错事。

所以在mysingleton.py中:

1
2
3
4
5
6
7
8
9
10
11
12
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

然后这样使用:

1
2
3
from mysingleton import Singleton

# Use it!

我说你必须付出额外的努力去做错事。下面是如何创建singleton类的两个实例,使其不再是singleton类:

1
another_instance = Singleton.__class__()

那么,如何避免这个问题呢?我引用医生的话:那就不要这样做!

注意:这是在下面的评论之后添加的

当我在这里的时候,这里有另一个单例变量,它最小化了复杂代码的数量。它使用元类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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中,您将创建这样的单例实例:

1
2
class Singleton(metaclass=SingletonMeta):
    attribute ="One... two... five!"

现在这个有点不确定了,因为singleton是一个类,您可以创建singleton的实例。从理论上讲,这是可以的,因为即使有实例,单体仍然是单体,但您需要记住,Singleton()不是单体,Singleton是!它甚至可以满足您的需要,让单例属性作为类属性随时可用于其实例。


另一种方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
>>> 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__的多个调用,那么可以选择使用decorator或元类。

重写__new__方法允许多次__init__调用,因为如果返回的值是该类的实例,python总是调用__new__返回的对象的__init__方法。

Anyway I think using a decorator it's the best thing, because it's probably the simpler solution.

如果您想了解更多在Python中创建单例的方法,请阅读这个问题。

顺便说一下,如果您希望所有实例都具有相同的状态(而不是标识),那么您可能会对Borg模式感兴趣。如果您不确定要选择哪一个,请参阅此答案。