为何Python单例模式代码执行结果不符合预期?
单例模式下实例属性被覆盖的原因分析
问题描述
我用Python实现了Singleton(单例)设计模式,预期先初始化的实例b的number值在4-33区间,后初始化的实例a的number值在100-200区间,但实际输出两者数值相同(比如148 148)。代码如下:
import random class Rng: _instance = None def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = super(Rng, cls).__new__(cls) return cls._instance def __init__(self, a, b): self.number = random.randint(a, b) b = Rng(4, 33) a = Rng(100, 200) print(a.number , b.number)
输出结果:
output: 148 148
原因解释
你实现的单例模式保证了整个程序中只会存在一个Rng类的实例,问题出在Python的实例创建流程上:
- 第一次调用
Rng(4,33)时,__new__方法检测到_instance为空,创建了第一个实例;紧接着__init__方法执行,给这个实例的number赋值为4-33之间的随机数。 - 第二次调用
Rng(100,200)时,__new__方法直接返回已经存在的那个实例,但**__init__方法会再次被调用**,把这个唯一实例的number重新赋值为100-200之间的随机数。 - 变量
a和b其实指向的是同一个对象,所以打印出来的number自然是最后一次__init__赋值的结果。
解决办法
方案1:仅首次创建实例时初始化属性
如果只需要单例实例的一个固定随机值,修改__init__逻辑,让它只在实例首次创建时执行初始化:
import random class Rng: _instance = None _initialized = False def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = super(Rng, cls).__new__(cls) return cls._instance def __init__(self, a, b): if not self._initialized: self.number = random.randint(a, b) self._initialized = True b = Rng(4, 33) a = Rng(100, 200) print(a.number , b.number) # 输出4-33之间的随机数,两次打印相同
方案2:存储不同参数对应的随机值
如果需要保留不同参数对应的随机值,同时维持单例,可以用字典存储参数与值的映射:
import random class Rng: _instance = None _param_values = {} def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = super(Rng, cls).__new__(cls) return cls._instance def __init__(self, a, b): param_key = (a, b) if param_key not in self._param_values: self._param_values[param_key] = random.randint(a, b) self.current_number = self._param_values[param_key] b = Rng(4, 33) a = Rng(100, 200) print(a.current_number , b.current_number) # 分别输出100-200和4-33的随机数
内容的提问来源于stack exchange,提问作者Emam Kownine
相关产品推荐
相关产品推荐

