恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
《单例模式的“四世同堂”:从 new 到装饰器再到模块,总有一种写法能让你面试吹牛》
首页
资讯中心
/
《单例模式的“四世同堂”:从 new 到装饰器再到模块,总有一种写法能让你面试吹牛》
《单例模式的“四世同堂”:从 new 到装饰器再到模块,总有一种写法能让你面试吹牛》
发布时间:2026/8/10 20:17:09
一、开篇一个类只生一个“娃”单例模式Singleton是设计模式中最专一的存在——无论你实例化多少次它永远只返回那一个对象。现实场景数据库连接池全局唯一节省资源项目配置文件管理器全局唯一避免配置不同步日志记录器全局唯一防止日志文件写入冲突今天我们把 Python 中实现单例的四种正统姿势全部摊开并深扒构造函数__new__与析构函数__del__的爱恨情仇。二、必修课彻底搞懂__new__与__init__在写单例前先理清这两个家伙的区别__new__(cls)真正的构造函数。负责在内存中分配空间并返回实例self。__init__(self)初始化函数。负责给实例填充数据属性赋值。打个比方__new__是买了一块空地盖房子__init__是装修房子贴瓷砖、买家具。class Demo: def __new__(cls): print(1. 构造中...分配内存) return super().__new__(cls) def __init__(self): print(2. 初始化中...填充数据)三、姿势①经典__new__覆写法最直观class Singleton: _instance None def __new__(cls): if cls._instance is None: cls._instance super().__new__(cls) return cls._instance s1 Singleton() s2 Singleton() print(s1 is s2) # True四、姿势②类方法获取单例封装调用class Singleton: _instance None def __new__(cls): if cls._instance is None: cls._instance super().__new__(cls) return cls._instance classmethod def get_instance(cls): return cls() # 内部调用 __new__ # 调用更语义化 s Singleton.get_instance()五、姿势③装饰器大法最 Pythonic装饰器可以不改变类的任何代码凭空给它加上单例能力def singleton(cls): instances {} def get_instance(): if cls not in instances: instances[cls] cls() return instances[cls] return get_instance singleton class Manager: pass m1 Manager() m2 Manager() print(m1 is m2) # True优点符合“开放-封闭”原则对扩展开放对修改关闭。六、姿势④模块导入法官方悄悄推荐Python 的模块天生就是单例因为一个.py文件在整个解释器生命周期内只会被导入一次。# mysingleton.py class _Manager: def __init__(self): self.data [] manager _Manager() # 直接创建好实例 # 其他文件调用 from mysingleton import manager # 无论导入多少次都是同一个对象这是 Python 官方文档中推荐的最简单、最可靠的单例实现方式没有之一七、进阶扩展①多线程下的“双重检查锁”面试必考上面的单例在多线程环境下可能失效if cls._instance is None不是原子操作。Web 后端必须加锁import threading class Singleton: _lock threading.Lock() _instance None def __new__(cls): if cls._instance is None: with cls._lock: # 加锁保证线程安全 if cls._instance is None: # 双重检查 cls._instance super().__new__(cls) return cls._instance八、进阶扩展②关于__del__析构函数的血泪教训在93.构造函数与析构函数.py中我们看到了__del__。但千万不要依赖它去释放重要资源如关闭数据库连接原因对象存在循环引用时__del__可能永远不会被调用Python 的垃圾回收器无法决定先删除谁。解释器退出时全局变量可能已被销毁__del__会访问不到必要的数据而报错。替代方案显式调用close()方法或者使用上下文管理器with语句。class Resource: def __enter__(self): print(打开资源) return self def __exit__(self, exc_type, exc_val, exc_tb): print(释放资源安全可靠) with Resource() as r: pass # 退出 with 块时自动执行 __exit__ 终极总结与面试彩蛋实现方式优点缺点__new__改写直观易懂子类继承需重写装饰器不入侵原类优雅返回的是函数类型可能改变模块导入极简、线程安全、官方推荐不太像“类的实例化”元类 (Metaclass)终极方案控制类创建过程学习成本高容易过设计面试高频题__new__和__init__谁先执行如果__new__返回了一个已有的对象__init__还会执行吗答案__new__先执行。如果__new__返回的不是当前cls的实例那么__init__不会被调用。