Python 单例行为很奇怪

问题描述 投票:0回答:1

我找到了创建单例类的最流行的方法之一,使用 _instance 和重写 __new__ 方法。这是:

class Singleton:
    _instance = None

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

但是当我尝试以这种方式使用它时,它表现得很奇怪:

class Child(Singleton):
    def __init__(self):
        self.a = random.randint(10, 1000)
x = Child()
y = Child()
print(x.__dict__)        # {'a': 74}
print(y.__dict__)        # {'a': 74}  - not weird
print(Child().__dict__)  # {'a': 222} - weird (for me)

有人可以解释为什么会发生吗?

PS:我使用的是python 3.10

python python-3.x singleton
1个回答
0
投票

一个答案

为了创建一个对象,Python 首先在其类上调用

__new__
,然后在该对象上调用
__init__

当您“创建”

Child
的实例时,Python将调用
Singleton.__new__
,然后调用
Child.__init__
。但是
Singleton.__new__
总是返回同一个对象
_instance
,因此
Child.__init__
总是会重新初始化同一个对象。

x
y
包含相同的对象,因为所有
Child
都是相同的对象。这就是为什么
x.__dict__
y.__dict__
是相同的。但是当你第三次调用
Child
时,它会重新初始化该对象,更改其字典。
print(Child().__dict__)
给出不同的值,因为它在打印之前调用
Child

并不是第三次调用

Child
会产生不同的对象;而是会产生不同的对象。相反,对象本身发生了变化。

关于单例的一些注意事项

如果您以这种方式实现单例,则不应使用

__init__
,因为每次调用
Child
时都会调用它并重新初始化对象。如果您需要初始化单例的值,您可以在 if 语句中的
__new__
中执行此操作,以便初始化仅完成一次。

还要考虑为什么需要创建单例的子类。一个单例应该只有一个成员,所以如果有任何

Child
的实例,那么所有
Singleton
一定都是
Child
,所以
Singleton
Child
最好合并到一节课。

© www.soinside.com 2019 - 2024. All rights reserved.