Python单例模式有四种主流实现:1.__new__方法(推荐,支持继承、懒加载,线程不安全);2.装饰器(灵活复用,不支持继承);3.模块级单例(最Pythonic,线程安全但无法动态控制初始化);4.元类(强大但复杂,适合深度定制)。
Python 实现单例模式有多种方式,核心目标是:确保一个类只有一个实例,并提供全局访问点。不同写法在可读性、线程安全、兼容性(如继承、装饰器)、以及是否支持懒加载等方面各有侧重。
1. 使用
__new__
方法(推荐,原生可控)
重写类的
__new__
是最直接、最符合 Python 习惯的方式。它在实例创建前介入,天然适合控制实例生成逻辑。
说明:通过类变量缓存实例,
__new__
检查是否存在,存在则直接返回,否则调用父类
__new__
创建新实例。
示例:
立即学习
“
Python免费学习笔记(深入)
”;
✅ 支持继承(子类需注意重置
_instance
或使用更健壮的实现)
✅ 线程不安全(多线程下可能重复创建;加锁可修复,但影响性能)
✅ 懒加载(首次调用时才创建)
⚠️ 注意:如果类定义了
__init__
,每次实例化都会执行——即使返回的是已有实例
2. 使用装饰器(灵活复用,语义清晰)
把单例逻辑抽离为装饰器,可作用于任意类,解耦性好,适合项目中统一管理。
示例:
立即学习
“
Python免费学习笔记(深入)
”;
✅ 语法简洁,装饰即生效
✅ 天然支持带参初始化(因每次调用仍走
__init__
,需额外处理避免重复初始化)
⚠️ 类本身失去“类型直觉”(
isinstance(db, Database)
仍成立,但 IDE 可能提示类型丢失)
⚠️ 不支持继承(被装饰后,子类无法自动获得单例行为)
3. 使用模块级单例(最 Pythonic,隐式但高效)
Python 模块天然单例:模块导入一次,对象只初始化一次。这是官方文档也认可的“Python 方式”。
Python 3.14.3
微软官方的 Python 扩展,是 VS Code 安装量最高的扩展(209M+)。集成 IntelliSense(通过 Pylance)、调试(通过 Python Debugger)、代码检查、格式化、重构和单元测试等功能。支持 Jupyter Notebook、虚拟环境管理和多 Python 版本切换。
下载
做法:把类实例直接定义在模块中,或直接用模块变量代替类。
示例(
config.py
):
✅ 绝对线程安全(模块加载是原子的)
✅ 零开销、无侵入、易测试
✅ 自动懒加载(首次 import 时触发)
⚠️ 不能动态控制初始化时机(比如依赖环境变量后再创建)
⚠️ 不是“类级别的单例”,而是“模块级别的单例”——如果你需要的是类行为(如继承、方法重载),它不适用
4. 使用元类(强大但复杂,慎用)
元类在类创建阶段介入,适合需要深度定制类行为的场景,但可读性和维护成本高。
示例:
立即学习
“
Python免费学习笔记(深入)
”;
✅ 对所有子类自动生效(只要指定同一元类)
✅ 可统一拦截所有单例类的实例化过程
⚠️ 元类概念较重,新手难理解,调试困难
⚠️ 与装饰器、
__new__
混用易出冲突
总结来看:日常开发优先考虑
__new__
写法或模块级单例;需要跨多个类复用逻辑时选装饰器;仅当架构层有强定制需求才用元类。没有绝对“最好”,只有“最合适”。
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def singleton(cls):
instances = {}
def get_instance(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return get_instance
@singleton
class Database:
def init(self):
print("Database initialized")
class Config:
def __init__(self):
self.debug = True
config = Config() # 模块加载时创建,全局唯一
class SingletonMeta(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super().__call__(*args, **kwargs)
return cls._instances[cls]
class Logger(metaclass=SingletonMeta):
pass
