Python基于__new__实现的单例模式表现异常,求原因解释
单例类继承后的异常行为解析
我发现一种创建单例类的主流实现方式,即使用_instance属性并重写__new__方法,代码如下:
class Singleton: _instance = None def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = super().__new__(cls) return cls._instance
但当我按如下方式使用时,它表现出奇怪的行为:
import random 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} - 这部分符合预期 print(Child().__dict__) # {'a': 222} - 这部分让人困惑
背后的原因
- 单例的核心逻辑:
Singleton的__new__方法保证每次调用类构造时,都会返回同一个_instance对象,所以x和y指向的是同一个实例,它们的属性字典自然完全一致。 __init__的执行规则:Python中,每次调用类构造(比如Child())时,不管实例是否已经存在,都会自动执行该实例的__init__方法。__new__负责创建实例,__init__负责初始化实例,二者是独立的步骤。Child().__dict__变化的本质:当你调用Child()时,返回的还是之前的单例实例,但此时会再次触发__init__方法,重新给self.a赋值为新的随机数。你打印的是执行完这次初始化后的属性字典,所以看到的是新的数值。- 直观验证:如果在打印
Child().__dict__后再查看x的属性,会发现x的a值也变成了222——因为它们从始至终都是同一个对象:
x = Child() print(x.__dict__) # {'a': 74} print(Child().__dict__) # {'a': 222} print(x.__dict__) # {'a': 222}
解决思路
如果希望单例实例只被初始化一次,可以在类中添加初始化标记,控制__init__的执行次数。比如修改Singleton基类:
class Singleton: _instance = None _initialized = False def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = super().__new__(cls) return cls._instance def __init__(self): if not self._initialized: # 这里放置需要只执行一次的初始化逻辑 self._initialized = True
或者在Child子类中添加类似的判断逻辑,确保__init__仅在实例首次创建时执行。
内容的提问来源于stack exchange,提问作者llownall
相关产品推荐
相关产品推荐

