可继承单例:如何通过元类确保__init__仅执行一次?
单例元类中避免父类__init__重复执行的解决方案
需求背景
- 实现
SingletonMeta元类,让任意类及所有派生类都成为单例 - 父类(如A)的
__init__中需分配依赖运行时参数的资源,且该资源整个程序生命周期仅分配一次,不受子类实例化时的super()调用影响
现有问题
现有单例元类实现能保证类及派生类的单例特性,但子类实例化时,通过super()调用父类__init__会导致父类的资源分配逻辑重复执行。
现有代码:
class SingletonMeta(type): _instances = {} def __call__(cls, *args, **kwargs): if cls not in cls._instances: instance = super().__call__(*args, **kwargs) cls._instances[cls] = instance return cls._instances[cls] class A(metaclass=SingletonMeta): def __init__(self, resource_name): print(resource_name) class B(A): def __init__(self, resource_name): super().__init__(resource_name) print(resource_name) def main(): a = A("A") b = B("B") if __name__ == "__main__": main()
输出为:
A A B
不符合预期,需要输出:
A B
解决方案
通过修改SingletonMeta元类,在类初始化阶段包装其__init__方法,添加类级别的初始化状态检查,确保每个类的__init__仅执行一次。
修改后的元类代码:
class SingletonMeta(type): _instances = {} # 记录已完成初始化的类 _initialized_classes = set() def __init__(cls, name, bases, attrs): super().__init__(name, bases, attrs) # 包装原__init__方法,添加执行控制逻辑 original_init = cls.__init__ def wrapped_init(self, *args, **kwargs): if cls not in SingletonMeta._initialized_classes: original_init(self, *args, **kwargs) SingletonMeta._initialized_classes.add(cls) cls.__init__ = wrapped_init def __call__(cls, *args, **kwargs): if cls not in cls._instances: instance = super().__call__(*args, **kwargs) cls._instances[cls] = instance return cls._instances[cls]
效果验证
使用原有的A、B类及测试代码运行,输出结果为:
A B
完全符合需求,且无需修改A、B的任何代码。
内容的提问来源于stack exchange,提问作者Gulzar
相关产品推荐
相关产品推荐

