首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >状态Python中的单例设计模式

状态Python中的单例设计模式
EN

Stack Overflow用户
提问于 2015-10-20 17:50:40
回答 2查看 1.4K关注 0票数 0

我试图用Python实现一个单例,在阅读了这个职位之后,我发现自己比以前更加困惑了。答案太多了,他们中的许多人已经获得了相当多的选票。现在的问题可能不是我有一个单例,而是状态只能初始化一次这一事实。我尝试了几个实现SingletonASingletonB,但我无法管理它的工作。对于我真正的问题,__init__函数很重,所以我只需要做一次。到目前为止,这就是我所拥有的:

代码语言:javascript
复制
class ClassA:

    def __init__(self):

        # some state
        print("Creating state in A")
        self.X = 1.
        self.Y = 2.

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


class ClassB:

    __shared_state = {}

    def __init__(self):

        if not bool(ClassB.__shared_state):

            # some state
            print("Creating state in B")
            self.X = 1.
            self.Y = 2.

        self.__dict__ = self.__shared_state


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

@singleton
class SingletonB(ClassB):
    pass

if __name__ == "__main__":

    a1 = SingletonA()
    a2 = SingletonA()
    if (id(a1) == id(a2)):
        print("Same",a1.X, a1.Y)
    else:
        print("Different",a1.X, a1.Y)

    b1 = SingletonB()
    b2 = SingletonB()
    if (id(b1) == id(b2)):
        print("Same",b1.X, b1.Y)
    else:
        print("Different",b1.X, b1.Y)

现在这是印刷:

代码语言:javascript
复制
$ python singleton.py 
Creating state in B
Creating state in B
Same 1.0 2.0
Creating state in A
Creating state in A
Same 1.0 2.0

指出事实上,我确实有一个单例类,但我希望避免状态的创建。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-10-20 19:12:32

这不能工作,因为__init__方法是在通过__new__创建对象之后调用的。Python语言引用提取液

如果__new__()返回一个cls实例,那么将像调用__init__(self[, ...])一样调用新实例的__init__()方法,其中self是新实例,其余参数与传递给__new__()的参数相同。

相反,您应该有一个与__init__不同的特殊初始化方法,并调用_instance创建。

代码可以是(不需要父类,所以我省略了它):

代码语言:javascript
复制
class SingletonA:
    _instance = None
    def __init__(self):

        # some state
        print("Creating dummy state in SingletonA")

    def _init(self):

        # some state
        print("Creating state in SingletonA")
        self.X = 1.
        self.Y = 2.
    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super(SingletonA, cls).__new__(
                cls, *args, **kwargs)
            cls._instance._init()
        return cls._instance

但实际上,您只需在声明时构建实例:

代码语言:javascript
复制
class SingletonA:
    def __init__(self):

        # some state
        print("Creating dummy state in SingletonA")

    def _init(self):

        # some state
        print("Creating state in A")
        self.X = 1.
        self.Y = 2.
    def __new__(cls, *args, **kwargs):
        return cls._instance

SingletonA._instance = super(SingletonA, SingletonA).__new__(SingletonA)
SingletonA._instance._init()

这两种方法都会导致以下输出(对于SingletonA部分):

代码语言:javascript
复制
Creating state in A
Creating dummy state in SingletonA
Creating dummy state in SingletonA
('Same', 1.0, 2.0)

完全删除__init__方法将导致一次初始化。

注释版本可以是:

代码语言:javascript
复制
class ClassB:

    def __init__(self):

            # some state
            print("Creating state in B")
            self.X = 1.
            self.Y = 2.


def singleton(cls):
    obj = cls()
    # Always return the same object
    cls._instance = obj
    cls.__new__ = staticmethod(lambda cls: cls._instance)
    # Disable __init__
    cls.__init__ = (lambda self: None)
    return cls

@singleton
class SingletonB(ClassB):
    pass

简单地将单例实例存储在类本身中。

票数 1
EN

Stack Overflow用户

发布于 2015-10-20 18:49:32

如果我对你的理解正确,这就是你所需要的:

代码语言:javascript
复制
# edited according to discussion in comments
class C:
    _shared_dict = None
    def __init__(self):
        if self._shared_dict is None:
            print("initializing")
            self.x = 1 
            self.y = 2 
            self.__class__._shared_dict = self.__dict__
        else:
            self.__dict__ = self._shared_dict

a=C()
b=C()

print(id(a), a.x, a.y)
print(id(b), b.x, b.y)

所有实例都将共享相同的数据,该数据将只计算一次。

请注意,在读取时,您可以将共享数据引用为self._shared_dict,但在写入类属性self.__class__._shared_dict时必须使用它的全名。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33243454

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档