Python面向对象之单例模式的四大实现方法详解

 更新时间:2026年10月03日 08:27:53   作者:星河耀银海  
本文将用通俗易懂的方式为大家详细介绍Python中单例模式的四种实现方法,包括__new__、装饰器、元类和模块并对比优缺点,通过日志管理器和数据库连接池实战案例,帮你彻底掌握单例模式,写出更高效的代码

一、开篇:只能有一个实例的类 

单例模式(Singleton)是最常用的设计模式之一:保证一个类只有一个实例,并提供全局访问点。典型的场景包括:数据库连接池、配置管理器、日志器、应用状态管理器。

先看一个直观的需求:

# 问题:全局配置应该只有一个实例
# 如果每个模块都创建新的Config对象,配置就会不一致
# ❌ 多个实例——配置不一致
# config1 = AppConfig()  # debug=True
# config2 = AppConfig()  # debug=False —— 这是另一个配置了!
# ✅ 单例——只有一个实例
# config1 = AppConfig()  # 创建实例
# config2 = AppConfig()  # 返回同一个实例
# config1 is config2     # True —— 同一个对象

二、Python实现单例的四种方式

2.1 使用__new__(最常用)

class Singleton:
    """单例——通过__new__控制实例创建"""
    _instance = None
    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            cls._instance._initialized = False
        return cls._instance
    def __init__(self, value=None):
        # ⚠️ __init__每次都会调用!需要防护
        if self._initialized:
            return
        self.value = value
        self._initialized = True
# 测试
s1 = Singleton("第一次")
s2 = Singleton("第二次")
print(s1 is s2)        # True —— 同一个实例
print(s1.value)        # 第一次 —— __init__只执行了一次
print(s2.value)        # 第一次

2.2 使用装饰器

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, connection_string="default"):
        self.connection_string = connection_string
        print(f"创建数据库连接: {connection_string}")
# 测试
db1 = Database("mysql://localhost/mydb")
db2 = Database("postgresql://localhost/testdb")
print(db1 is db2)                 # True
print(db1.connection_string)     # mysql://localhost/mydb
print(db2.connection_string)     # mysql://localhost/mydb
# ⚠️ 装饰器方式的缺点:
# Database现在是一个函数而不是类
print(type(Database))  # <class 'function'>
# isinstance检查不适用

2.3 使用元类(最彻底的实现)

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 Config(metaclass=SingletonMeta):
    """配置管理器——单例(通过元类)"""
    def __init__(self, debug=False):
        # 不需要_initialized防护——元类控制__init__只调用一次
        self.debug = debug
        self.settings = {}
        print(f"Config初始化: debug={debug}")
# 测试
c1 = Config(debug=True)
c2 = Config(debug=False)
print(c1 is c2)      # True
print(c1.debug)      # True —— 第一次初始化的值
print(c2.debug)      # True
# 💡 元类方式最优雅——类定义时就决定了单例行为
# __init__自动只执行一次

2.4 使用模块(Pythonic方式)

# 💡 Python的模块本身就是单例!
# 模块在第一次导入时执行,之后被缓存到sys.modules
# 这是最"Pythonic"的单例实现方式
# ===== config.py =====
"""
class AppConfig:
    def __init__(self):
        self.debug = False
        self.host = "localhost"
        self.port = 8080
    def set_debug(self, enabled):
        self.debug = enabled
# 在模块级别创建实例——这就是单例!
config = AppConfig()
"""
# ===== main.py =====
# from config import config
# 
# # 所有地方导入的都是同一个config对象
# config.set_debug(True)
# 
# # 另一个文件
# from config import config
# print(config.debug)  # True —— 同一个对象
# 💡 优点:简单、不需要任何特殊语法
# 💡 缺点:导入时即创建(不能延迟)、无法传参构造

三、单例的实战应用

3.1 日志管理器

import threading
from datetime import datetime
class Logger(metaclass=SingletonMeta):
    """日志管理器——全局唯一"""
    def __init__(self):
        self._lock = threading.Lock()
        self._handlers = []
        self._level = "INFO"
    def set_level(self, level):
        self._level = level
    def add_handler(self, handler):
        self._handlers.append(handler)
    def log(self, message, level="INFO"):
        """线程安全的日志记录"""
        with self._lock:
            timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
            log_entry = f"[{timestamp}] [{level}] {message}"
            # 输出到所有处理器
            for handler in self._handlers:
                handler(log_entry)
            # 默认输出到控制台
            if not self._handlers:
                print(log_entry)
# 使用——在任何地方获取同一个Logger
def some_function():
    logger = Logger()
    logger.log("函数执行中...")
def another_function():
    logger = Logger()
    logger.log("另一个函数执行中...", level="WARNING")
some_function()
another_function()

3.2 数据库连接池

from threading import Lock
class ConnectionPool(metaclass=SingletonMeta):
    """数据库连接池——全局唯一"""
    def __init__(self, max_connections=10):
        self.max_connections = max_connections
        self._connections = []
        self._in_use = set()
        self._lock = Lock()
        print(f"连接池创建: 最大{max_connections}个连接")
    def get_connection(self):
        """获取一个连接"""
        with self._lock:
            if len(self._connections) < self.max_connections:
                conn = f"连接-{len(self._connections) + 1}"
                self._connections.append(conn)
            else:
                raise RuntimeError("连接池已满")
            self._in_use.add(conn)
            return conn
    def release_connection(self, conn):
        """释放连接"""
        with self._lock:
            self._in_use.discard(conn)
    def status(self):
        return {
            "total": len(self._connections),
            "in_use": len(self._in_use),
            "available": len(self._connections) - len(self._in_use),
        }
# 使用
pool = ConnectionPool(max_connections=5)
conn1 = pool.get_connection()
conn2 = pool.get_connection()
print(pool.status())  # {'total': 2, 'in_use': 2, 'available': 0}
pool.release_connection(conn1)
print(pool.status())  # {'total': 2, 'in_use': 1, 'available': 1}

四、总结

单例模式保证"只有一个实例"。Python提供了多种实现——从简单的模块到彻底的元类。

四种实现对比:

方式优点缺点
__new__简单直观需要防__init__重复
装饰器简洁类型变成函数
元类最彻底稍复杂
模块最Pythonic不能延迟创建

日常推荐:模块级别实例(最简单)→ __new__方式(需要传参)→ 元类(框架/库)。

到此这篇关于Python面向对象之单例模式的四大实现方法详解的文章就介绍到这了,更多相关Python单例模式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 利用Python实现一个简易的截图工具

    利用Python实现一个简易的截图工具

    这篇文章主要为大家详细介绍了如何利用Python实现一个简易的截图工具,可以截完图之后显示并且永远前置,感兴趣的小伙伴可以尝试一下
    2022-07-07
  • 关于pytorch训练分类器

    关于pytorch训练分类器

    这篇文章主要介绍了关于pytorch训练分类器问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-09-09
  • 一文详解Python函数的返回值(return)与多值返回

    一文详解Python函数的返回值(return)与多值返回

    本章深入探讨Python函数的返回值与多值返回,介绍核心概念、应用场景、技术原理及实践应用,掌握这些技能可提升开发效率与代码质量,需要的朋友可以参考下
    2026-06-06
  • Python超参数优化的实战方法

    Python超参数优化的实战方法

    在机器学习模型开发中,超参数优化是提升模型性能的关键环节,本文聚焦Python超参数优化的实战方法,结合最新工具案例,揭示如何通过科学调参实现模型性能跃升,需要的朋友可以参考下
    2025-12-12
  • Django logging配置及使用详解

    Django logging配置及使用详解

    这篇文章主要介绍了Django logging配置及使用详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-07-07
  • Python NLP开发之实现聊天机器人

    Python NLP开发之实现聊天机器人

    这篇文章主要为大家介绍了Python如何实现聊天机器人,即使用自然语言处理 (NLP) 来帮助用户通过文本、图形或语音与 Web 服务或应用进行交互,感兴趣的可以了解一下
    2023-05-05
  • python神经网络MobileNetV3 large模型的复现详解

    python神经网络MobileNetV3 large模型的复现详解

    这篇文章主要为大家介绍了python神经网络MobileNetV3 large模型的复现详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-05-05
  • python3 自动打印出最新版本执行的mysql2redis实例

    python3 自动打印出最新版本执行的mysql2redis实例

    这篇文章主要介绍了python3 自动打印出最新版本执行的mysql2redis实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-04-04
  • 利用Python读取微信朋友圈的多种方法总结

    利用Python读取微信朋友圈的多种方法总结

    这篇文章主要给大家介绍了关于如何利用Python读取微信朋友圈的多种方法,对于一个新手来说如果单独的去爬取朋友圈的话,难度会非常大,可以借鉴这篇文章的内容,需要的朋友可以参考下
    2021-08-08
  • 基于Python绘制一个会动的3D立体粽子

    基于Python绘制一个会动的3D立体粽子

    下周就要到端午节了,所以本文小编就来和大家分享一个有趣的Python项目——绘制会动的3D立体粽子,文中的示例代码讲解详细,感兴趣的可以了解一下
    2023-06-06

最新评论