__new__ 更适合实现单例,因为它在对象创建阶段介入,可控制是否复用实例;而 __init__ 每次都会执行,无法避免重复构造开销。

为什么 __new__ 比 __init__ 更适合实现单例
因为 __new__ 在对象创建阶段就介入,能决定是否复用已有实例;而 __init__ 每次都会被调用,无法阻止重复初始化。如果你在 __init__ 里做判空并 return,实际已经生成了新对象——只是没执行后续逻辑,内存和构造开销白花了。
常见错误是把单例逻辑写在 __init__ 里,结果发现每次调用类名都新建实例,is 判断失败。
-
__new__接收的第一个参数是cls,必须显式调用父类的__new__(通常是object.__new__(cls))来获取实例 - 返回值必须是该类的实例(或其子类),否则
__init__不会触发 - 类变量(如
_instance)用于存储唯一实例,需在__new__开头检查
基础单例:带线程安全的 __new__ 实现
不加锁的版本在多线程下可能创建多个实例——两个线程几乎同时通过 if cls._instance is None 判断,各自执行 super().__new__(cls)。
标准做法是用 threading.Lock 包裹实例创建逻辑:
立即学习“Python免费学习笔记(深入)”;
import threading
<p>class Singleton:
_instance = None
_lock = threading.Lock()</p><pre class="brush:php;toolbar:false;">def __new__(cls):
if cls._instance is None:
with cls._lock:
if cls._instance is None: # 双重检查
cls._instance = super().__new__(cls)
return cls._instance
注意第二次 if cls._instance is None 不可省略:防止锁内已有其他线程完成赋值,避免重复创建。
支持继承的单例:用 cls 而非硬编码类名
如果写成 Singleton._instance,子类调用时会共享父类的 _instance,导致子类无法拥有独立单例。必须用 cls._instance 和 cls._lock,让每个类维护自己的状态。
但 Python 类变量默认是继承共享的,所以需要在子类中显式定义:
class DatabaseConnection(Singleton):
_instance = None
_lock = threading.Lock()
更稳妥的方式是用字典按类名隔离:
_instances = {}
_locks = {}
<p>def <strong>new</strong>(cls):
if cls not in _instances:
if cls not in _locks:
_locks[cls] = threading.Lock()
with _locks[cls]:
if cls not in _instances:
_instances[cls] = super().<strong>new</strong>(cls)
return _instances[cls]
这种写法消除了子类手动声明的负担,但增加了全局字典的维护成本。
__new__ 单例与 @classmethod 工厂方法的本质区别
有人用 @classmethod 返回缓存实例,比如 cls.get_instance()。这不是单例模式——它没控制 MyClass() 的行为,用户仍可绕过方法直接构造新对象。
__new__ 是唯一能拦截 MyClass() 调用的钩子。只要类定义了它,所有常规实例化都会走这里,无需文档强调“请务必调用 get_instance”。
不过要注意:如果类有 __init__ 且依赖传参(如 __init__(self, host, port)),__new__ 无法阻止参数不一致带来的逻辑混乱——首次调用后,后续调用若传不同参数,__init__ 仍会执行(除非你也在 __init__ 加防护)。真正的单例通常应禁止初始化参数,或只允许首次传参生效。


















