You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用类变量与字典存储实例时,单例模式为何表现不同?

两种Base基类实现导致子类实例行为差异的原因分析

第一种实现的逻辑与结果

class Base:

    _instance: "Base" = None

    def __new__(cls) -> "Base":
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

class A(Base):
    def foo(self):
        return "foo"

class B(Base):
    def quz(self):
        return "quz"

a = A()
b = B()

print(id(a))
print(id(b))

输出:

140035075937792
140035075948400

原因

Python中,子类继承父类的类属性时,当子类对类属性进行赋值操作,会在子类自己的命名空间中创建独立的属性副本。
在这个实现里,__new__方法中操作的是cls._instance——cls是当前被实例化的子类(A或B)。实例化A时,A没有自己的_instance属性,会先读取Base的_instance(值为None),随后给A._instance赋值;实例化B时,同理操作的是B._instance。最终A和B各自拥有独立的实例存储,所以a和b是两个不同的对象,ID不同。

第二种实现的逻辑与结果

from typing import Dict

class Base:

    _instances: Dict[int, "Base"] = {}

    def __new__(cls) -> "Base":
        if 0 not in cls._instances:
            cls._instances[0] = super().__new__(cls)
        return cls._instances[0]

class A(Base):
    def foo(self):
        return "foo"

class B(Base):
    def quz(self):
        return "quz"

a = A()
b = B()

print(id(a))
print(id(b))

输出:

140035075947296
140035075947296

原因

这里的_instances是Base类的字典属性,子类A和B不会自动创建该属性的副本——因为代码中只对字典进行in判断和内部键值对赋值操作,没有直接给cls._instances重新赋值。
实例化A时,cls是A,A没有自己的_instances,会直接使用Base的_instances字典。此时字典中没有0这个键,所以创建A的实例存入Base._instances[0]。当实例化B时,cls是B,同样会读取Base的_instances字典,此时0键已经存在,直接返回字典里的A实例,所以b和a是同一个对象,ID完全相同。

内容的提问来源于stack exchange,提问作者Victor Wong

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 21:12:43