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

带构造参数的Python单例实现报错及逻辑疑问

带构造参数的单例实现问题与解决

问题描述

尝试实现支持构造参数的单例模式,但传递参数给元类时触发错误,同时对现有逻辑的有效性存在疑问:控制台显示元类的__init__和__call__先于MySingleton构造函数执行,输入参数被用于__call__中实例化最终单例self._myObject。

原代码

from typing_extensions import List, TypedDict, Optional, Any

class Singleton(type): # 继承type以获取__call__方法
    _var: str = None
    _myObject: Any = None  # 原代码中MyType未定义,此处改为Any
    def __init__(self, *args, **kwargs):
        print(f"Singleton::__init__")
        print(f"Singleton::__init__ len(kwargs): {len(kwargs)}, len(args): {len(args)}, args[0]: {args[0]}")
        print(**kwargs)
        for i in args:
            print(f"i: {i}")
        if "var" in kwargs and kwargs.get("var"):
            self._var = kwargs.get('var')
        elif len(args):
            self._var = args[0]
        else:
            self._var = "text-embedding-005"
        print(f"Singleton::__init__self._var: {self._var}")
        self.__instance = None # 存储实例引用的变量
        super().__init__(*args, **kwargs)

    def __call__(self, *args, **kwargs):
        if self.__instance is None:
            # 对象尚未创建时
            self._myObject = self._var  # 原代码MyType未定义,此处调整
            print(f"Singleton::__call__ self._var: {self._var}")
            self.__instance = super().__call__(*args, **kwargs)
            return self.__instance
        else:
            # 对象已存在时返回引用
            return self.__instance
            
class MySingleton(metaclass=Singleton):
    """
    类构造函数
    """
    def __init__(self, *args, **kwargs):
        print(f"MySingleton::__init__")
        super().__init__(*args, **kwargs)
        print(f"MySingleton::__init__ {self._var}")

myobject = MySingleton("hello")
myobject1 = MySingleton("world")

错误信息

Singleton::__init__
Singleton::__init__ len(kwargs): 0, len(args): 3, args[0]: MySingleton

i: MySingleton
i: ()
i: {'__module__': '__main__', '__qualname__': 'MySingleton', '__doc__': '\n    Class constructor\n', '__init__': <function MySingleton.__init__ at 0x7de2ca4fd800>, '__classcell__': <cell at 0x7de2ca5399f0: Singleton object at 0x12d21760>}
Singleton::__init__self._model: MySingleton
Singleton::__call__ _model: MySingleton
MySingleton::__init__
Traceback (most recent call last):
  File "singleton.py", line 43, in <module>
    vector_store = MySingleton("hello")
                   ^^^^^^^^^^^^^^^^^^^^
  File "singleton.py", line 26, in __call__
    self.__instance = super().__call__(*args, **kwargs)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "singleton.py", line 38, in __init__
    super().__init__(*args, **kwargs)
TypeError: object.__init__() takes exactly one argument (the instance to initialize)

问题分析

  1. 直接错误原因:MySingleton默认继承自object,其__init__调用super().__init__(*args, **kwargs)时传入了额外参数,但object.__init__仅接受self一个参数,触发类型错误。
  2. 元类逻辑错误:元类的__init__方法在定义MySingleton类时执行,其args是类定义的核心参数(类名、基类元组、类命名空间),并非实例化时传入的"hello"。原代码错误地将类定义参数当作实例化参数处理,导致_var被赋值为MySingleton类本身。
  3. 单例逻辑有效性问题:元类__init__仅在类创建时运行一次,无法获取实例化阶段的参数,原代码试图在此处处理实例化参数的逻辑完全错误。

修正后的实现

from typing import Any

class Singleton(type):
    _instance: Any = None
    _init_args: tuple = ()
    _init_kwargs: dict = {}

    def __call__(self, *args, **kwargs):
        if self._instance is None:
            # 保存第一次实例化的参数
            self._init_args = args
            self._init_kwargs = kwargs
            self._instance = super().__call__(*args, **kwargs)
        else:
            # 后续实例化忽略新参数(可改为抛出错误)
            if args != self._init_args or kwargs != self._init_kwargs:
                print(f"警告:单例已存在,将忽略新参数 {args}, {kwargs}")
        return self._instance

class MySingleton(metaclass=Singleton):
    def __init__(self, var: str):
        print(f"MySingleton::__init__ 传入参数: {var}")
        self._var = var

# 测试
myobject = MySingleton("hello")
print(f"myobject._var: {myobject._var}")
myobject1 = MySingleton("world")
print(f"myobject1._var: {myobject1._var}")
print(f"是否为同一实例: {myobject is myobject1}")

修正说明

  • 移除元类中错误的__init__逻辑,将参数处理移至__call__方法(实例化类时触发)。
  • 保存第一次实例化的参数,后续实例化时忽略新参数(可根据需求改为抛出错误)。
  • 移除MySingleton中多余的super().__init__(*args, **kwargs)调用,避免触发object.__init__的参数错误。
  • 明确MySingleton的构造参数类型,增强代码可读性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 23:10:20