Python实现单例模式的几种常见方式

 更新时间:2026年05月06日 09:34:20   作者:huzhongqiang  
本文分享 Python 单例模式四种实现方式(装饰器、new、函数、lru_cache),对比优缺点后建议优先显式获取单例,强调编程应回归朴素,避免过度设计,简单直白的代码更易维护,需要的朋友可以参考下

前言

最近在整理代码时,重新审视了项目中用到的单例模式实现。发现自己对单例模式的理解经历了一个有趣的循环:从懵懂使用,到追求各种"巧妙"实现,再到回归朴素。

今天想分享几种 Python 实现单例模式的方式,并谈谈我多年编程的一个感悟:朴素的就是最好的

一、单例模式简介

单例模式(Singleton Pattern)是一种设计模式,确保一个类只有一个实例,并提供一个全局访问点。

适用场景

场景说明
数据库连接全局共享一个连接池
日志记录器避免重复打开文件
配置管理器全局只读一份配置
缓存实例全局共享缓存

二、四种实现方式

方式一:类装饰器

def singleton(cls):
    """单例装饰器:闭包保存唯一实例"""
    _instance = None

    def wrapper(*args, **kwargs):
        nonlocal _instance
        if _instance is None:
            _instance = cls(*args, **kwargs)
        return _instance

    return wrapper


@singleton
class DBConnect:
    def __init__(self, host):
        self.host = host
        print("数据库连接初始化")


# 使用
obj1 = DBConnect("127.0.0.1")
obj2 = DBConnect("192.168.1.1")  # 不会重新初始化

print(obj1 is obj2)  # True
print(obj1.host)     # 127.0.0.1

特点:装饰器语法优雅,使用时一目了然。

方式二:__new__方法

class MySingleton:
    """单例类:通过 __new__ 控制实例创建"""
    _instance = None

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance


# 使用
obj1 = MySingleton()
obj2 = MySingleton()
print(obj1 is obj2)  # True

特点:最直接的方式,但 _instance 作为类变量暴露在外。我之前的博文 Playwright理解与封装就是使用这种方式,感觉不太好,准备重构一下,那个类根本不需要单例模式,如果使用者觉得有必要,可以显式自行单例化即可。

方式三:函数

from typing import Type, TypeVar

T = TypeVar('T')

def singleton(cls: Type[T], *args, **kwargs) -> T:
    """单例工厂函数"""
    if not hasattr(cls, '_instance'):
        cls._instance = cls(*args, **kwargs)
    return cls._instance


# 使用
class TargetClass:
    def __init__(self, config):
        self.config = config

obj = singleton(TargetClass, config="value")

特点:需要显式调用 singleton(),语义明确但稍显繁琐。

方式四:functools.lru_cache

from functools import lru_cache

@lru_cache(maxsize=1)
def get_instance():
    return MyClass(arg1="value")


# 使用
obj1 = get_instance()
obj2 = get_instance()
print(obj1 is obj2)  # True

特点:Python 内置,简单直接,还能享受缓存的好处。

三、优缺点对比

实现方式优点缺点推荐指数
类装饰器语法优雅、语义清晰、易于理解对于非必要实现单例的类,对使用者会造成困扰⭐⭐⭐⭐
new 方法最直观、最简单实例变量暴露、可复用性不好⭐⭐
单例函数显式调用、可控性强,使用者清楚知道正在做什么每次都要调用、不够直观⭐⭐⭐
lru_cache内置、无需额外代码语义上不是单例、更像缓存,但是胜在简单⭐⭐⭐⭐

四、我的建议

优先使用显式单例

相比把类变成单例,显式获取单例的写法更加清晰:

# ✅ 推荐:显式获取单例
_db = None
def get_db():
    global _db
    if _db is None:
        _db = Database()
    return _db

# 或者更简洁地用 lru_cache
@lru_cache
def get_db():
    return Database()
# ❌ 不推荐:把类变成单例,除非很确定此类必须是单例类,不会造成使用者误解
@singleton
class Database:
    ...

为什么?

  1. 透明性:使用者能清楚看到这个类是全局共享的
  2. 可控性:可以灵活控制何时创建、如何创建
  3. 易测试:mock 和替换更容易
  4. 少歧义:不会让使用者误以为每次 new 都是新实例

五、多年编程感悟

朴素的就是最好的。所有当时自鸣得意的所谓编程技巧,最后都会被证明要用更多的代价来理解和维护它。

几个教训

当年觉得"巧妙"后来发现的问题
复杂的继承链调试时一头雾水
动态修改类属性难以追踪状态变化
魔法装饰器新人看不懂
元编程炫技给自己挖坑

回归朴素

# 曾经的我:要用单例模式!
@singleton
class ConfigManager:
    ...

# 现在的我:简单就好
@lru_cache
def get_db():
    return Database()

简单、直白、不需要解释。这才是好的代码。

六、总结

要点回顾

  1. 装饰器方式是最推荐的类单例实现(针对必须实现单例的类)
  2. 显式获取单例比把类变成单例更好
  3. lru_cache 是最简单的单例缓存方案
  4. 朴素思维:能用简单方式解决的问题,不要过度设计

以上就是Python实现单例模式的几种常见方式的详细内容,更多关于Python实现单例模式的资料请关注脚本之家其它相关文章!

相关文章

  • 基于Python+Pyqt5开发一个应用程序

    基于Python+Pyqt5开发一个应用程序

    今天给大家带来的是关于Python的相关知识,文章围绕着Python+Pyqt5开发一个应用程序展开,文中有非常详细的介绍及代码示例,需要的朋友可以参考下
    2021-06-06
  • python3.X 抓取火车票信息【修正版】

    python3.X 抓取火车票信息【修正版】

    这篇文章主要介绍了python3.X 抓取火车票信息修正版,本文是在源代码的基础上进行的修改,需要的朋友可以参考下
    2018-06-06
  • Python使用SpeechRecognition库实现语音识别功能

    Python使用SpeechRecognition库实现语音识别功能

    SpeechRecognition 是 Python 生态中最主流的语音识别第三方库,它封装了多个国内外主流语音识别引擎的接口,本文将带大家了解Python的SpeechRecognition库的功能、使用方法,并通过具体案例掌握它在不同场景下的应用,需要的朋友可以参考下
    2026-01-01
  • Python中子类继承父类传递参数的方法

    Python中子类继承父类传递参数的方法

    在面向对象编程中,继承是一种使得一个类(称为子类)能够获取另一个类(称为父类)的属性和方法的机制,Python支持继承,并提供了灵活的方式来继承和扩展类的功能,本文将详细介绍如何在Python中使用子类继承父类,并传递参数,需要的朋友可以参考下
    2025-03-03
  • 线程安全及Python中的GIL原理分析

    线程安全及Python中的GIL原理分析

    这篇文章主要介绍了线程安全及Python中的GIL原理,较为详细的分析了线程安全及Python中的GIL相关概念、原理、理解及操作注意事项,需要的朋友可以参考下
    2019-10-10
  • Python3.x版本中新的字符串格式化方法

    Python3.x版本中新的字符串格式化方法

    这篇文章主要介绍了Python3.x版本中新的字符串格式化方法,本文对比给出了Python2.x和Python3.x中字符串格式化方法实例代码,需要的朋友可以参考下
    2015-04-04
  • selenium自动化测试框架方式

    selenium自动化测试框架方式

    这篇文章主要介绍了selenium自动化测试框架方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2020-02-02
  • Python +Selenium解决图片验证码登录或注册问题(推荐)

    Python +Selenium解决图片验证码登录或注册问题(推荐)

    这篇文章主要介绍了Python Selenium解决图片验证码登录或注册问题,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-02-02
  • 一波神奇的Python语句、函数与方法的使用技巧总结

    一波神奇的Python语句、函数与方法的使用技巧总结

    这篇文章主要介绍了一波神奇的Python函数与方法的使用技巧总结,包括装饰器和with语句等的不常见用法,需要的朋友可以参考下
    2015-12-12
  • python循环引用和解决过程

    python循环引用和解决过程

    文章讨论了在Python中解决循环引用问题的几种方法,包括延迟导入、使用`importlib`、重构代码和类型提示的前向引用,这些方法可以帮助开发者避免导入循环导致的错误,并使代码更加模块化和易于维护
    2025-12-12

最新评论