Python设计模式之创建型-单例模式(Singleton)

目录

作用

适用场景

使用模块

使用装饰器

使用元类

__new__方法单例模式

总结


图片

更多关于Python的相关技术点,敬请关注公众号:CTO Plus后续的发文,有问题欢迎后台留言交流。

图片

 注意:本代码示例环境Python版本使用最新的Python3.11

在前面的文章《关于Python设计模式的一些事情,设计模式是否真能帮你解决什么问题?》中对Python的设计模式进行了一个大体的分享介绍。本篇我将来总结下第一个设计模式,单例模式是一种创建型设计模式,它的目的是确保一个类只有一个实例,并提供一个全局访问点来访问该实例。在Python中,可以使用多种方法来实现单例模式,本文这里我将介绍其中几种常用的方法,包括使用模块、使用装饰器、使用元类、以及__new__方法。

【Python设计模式系列】

  1. 《关于Python设计模式的一些事情,设计模式是否真能帮你解决什么问题?》

  2. 《Python设计模式之创建型-单例模式(Singleton)》

  3. 《Python设计模式之创建型-简单工厂模式(Simple Factory)》

  4. 《Python设计模式之创建型-工厂方法模式(Factory Method)》

  5. 《Python设计模式之创建型-抽象工厂模式(Abstract Factory)》

  6. 《Python设计模式之创建型-创建者(建造者)模式(Builder)》

  7. 《Python设计模式之创建型-原型模式(Prototype)》

  8. 《Python设计模式之创建型-对象池模式(Pool)》

  9. 《Python设计模式之创建型-惰性评价模式(Lazy Evaluation)》

  10. 《Python设计模式之结构型-代理模式(Proxy)》

  11. 《Python设计模式之结构型-适配器模式(Adapter)》

  12. 《Python设计模式之结构型-装饰器模式(Decorator)》

  13. 《Python设计模式之结构型-组合模式(Composite)》

  14. 《Python设计模式之结构型-外观模式(Facade)》

  15. 《Python设计模式之结构型-享元模式(Flyweight)》

  16. 《Python设计模式之结构型-桥接模式(Bridge)》

  17. 《Python设计模式之结构型-3层模式(3-tier)》

  18. 《Python设计模式之结构型-前端控制器模式(front controller)》

  19. 《Python设计模式之结构型-MVC模式(mvc)》

  20. 《Python设计模式之行为型-观察者模式(Observer)》

  21. 《Python设计模式之行为型-模板方法(Template Method)模式》

  22. 《Python设计模式之行为型-策略模式(Strategy)》

  23. 《Python设计模式之行为型-职责链模式(Chain of Responsibility)》

  24. 《Python设计模式之行为型-状态模式(State)》

  25. 《Python设计模式之行为型-迭代器模式(Iterator)》

  26. 《Python设计模式之行为型-访问者(访客)模式(Visitor)》

  27. 《Python设计模式之行为型-命令模式(Command)》

  28. 《Python设计模式之行为型-解释器模式(Interpreter)》

  29. 《Python设计模式之行为型-调停者(中介者)模式(Mediator)》

  30. 《Python设计模式之行为型-备忘录模式(Memento)》

  31. 《Python设计模式之行为型-目录模式(catalog)》

  32. 《Python设计模式之行为型-方法链模式(chaining method)》

  33. 《Python设计模式之行为型-发布订阅模式(publish subscribe)》

  34. 《Python设计模式之行为型-注册模式(registry)》

  35. 《Python设计模式之行为型-规格模式(specification)》

作用

确保一个类只有一个实例,并提供一个全局访问点来获取该实例。

适用场景

  1. 当类只能有一个实例而且客户可以从一个众所周知的访问点(如全局变量、或一个全局配置)访问它时,例如数据库连接、日志记录等。

  2. 当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。

使用模块

在Python中,模块是天然的单例模式。当我们导入一个模块时,Python会确保该模块只被导入一次,并且在后续的导入中直接返回已经导入的模块对象。因此,我们可以将需要实现单例的类放在一个模块中,并通过导入该模块来获取该类的实例。

# singleton.py

import settings
class SingletonClass:    def __init__(self):        print(f"author:{settings.AUHTOR}")
    def do_something(self):        print(f"view {settings.BLOG}")
singleton_instance = SingletonClass()

# main.py

from singleton import singleton_instance
singleton_instance.do_something()

在上面的示例中,我们将需要实现单例的类SingletonClass放在了一个名为singleton.py的模块中,并创建了一个singleton_instance的全局变量来保存该类的实例。在main.py中,我们通过导入singleton_instance来获取该类的实例,并调用其方法。

图片

                     

这种方法的优点是实现简单,不需要考虑线程安全问题,且能够保证只有一个实例。然而,它的缺点是该实例在模块导入时就已经创建,无法在运行时动态创建实例。

使用装饰器

装饰器是Python中一种特殊的语法,它可以用来修饰函数、方法或类。我们可以使用装饰器来实现单例模式,通过装饰类的构造函数,使得每次创建对象时都返回同一个实例。

import settings
def singleton(cls):    instances = {}
    def wrapper(*args, **kwargs):        if cls not in instances:            instances[cls] = cls(*args, **kwargs)        return instances[cls]    return wrapper

@singletonclass SingletonClass:    def __init__(self):        print(f"Hello {settings.AUTHOR}")
    def do_something(self):        print(f"view blog {settings.BLOG}")

if __name__ == '__main__':    singleton_instance = SingletonClass()    singleton_instance.do_something()
    singleton_instance2 = SingletonClass()
    print(id(singleton_instance), id(singleton_instance2)) # 2658583849552 2658583849552    print(singleton_instance is singleton_instance2)  # True

在上面的示例中,我们定义了一个装饰器singleton,singleton是一个类装饰器,它接受一个类作为参数,并返回一个新的类。它使用一个字典instances来保存每个类的实例。在装饰的类的构造函数中,我们首先检查该类是否已经有实例,如果没有则创建一个新的实例并保存到instances字典中,然后返回该实例。

使用装饰器实现单例模式的优点是可以动态创建实例,并且能够保证只有一个实例。然而,它的缺点是不支持多线程,如果在多线程环境下同时创建多个实例,可能会出现竞争条件。

图片

使用元类

元类是Python中一种特殊的类,它用于创建其他类。我们可以使用元类来实现单例模式,通过修改元类的__call__方法,使得每次调用类时都返回同一个实例。

import settings# 使用元类来实现单例模式
class SingletonMeta(type):    _instance = {}
    def __call__(self, *args, **kwargs):        if self not in self._instance:            self._instance[self] = super(SingletonMeta, self).__call__()        return self._instance[self]

class SingletonClass(metaclass=SingletonMeta):    def __init__(self):        print(f"author {settings.AUTHOR}")
    def do_something(self):        print(f"view blog {settings.BLOG}")

if __name__ == '__main__':    singleton_instance = SingletonClass()    singleton_instance.do_something()
    singleton_instance2 = SingletonClass()    singleton_instance2.do_something()
    print(id(singleton_instance2), id(singleton_instance))  # 2666431948688 2666431948688    print(singleton_instance2 is singleton_instance) # True    print(singleton_instance2 == singleton_instance) # True

在上面的示例中,我们定义了一个元类SingletonMeta,它使用一个字典_instances来保存每个类的实例。在元类的__call__方法中,我们首先检查该类是否已经有实例,如果没有则创建一个新的实例并保存到_instances字典中,然后返回该实例。

使用元类实现单例模式的优点是可以动态创建实例,并且能够保证只有一个实例。它的缺点是较为复杂,需要理解元类的概念和使用方式。

__new__方法单例模式

我们可以通过修改类的__new__方法,使每次创建对象时都返回同一个实例。

class SingletonObject:    def __new__(cls, *args, **kwargs):        # 并将一个类的实例绑定到类变量_instance上        # 判断当前实例是否存在,如果前面已经有人实例过,则直接返回实例        if not hasattr(cls, '_instance'):            # 如果内存没有该实例 往下执行            # 需要注明该父类的内存空间内最多允许相同名字子类的实例对象存在1个(不可多个)
            origin_object = super(SingletonObject, cls)  # 父类            # origin_object让cls继承指定的父类Singleton            cls._instance = origin_object.__new__(cls)            # cls._instance 创建了该实例
        # 如果cls._instance不为None, 直接返回cls._instance        return cls._instance
class Person1(SingletonObject):    def __init__(self, name):        self.name = name
class Person2(SingletonObject):    def __init__(self, alias):        self.alias = alias
if __name__ == '__main__':    person1 = Person1(settings.AUTHOR)    print(person1.name)  # SteveRocket    person3 = Person1(settings.AUTHOR)    print(person3.name)  # SteveRocket    print(id(person1), id(person3))  # 2989265330704 2989265330704
    person3.name = 'Python3.11'    print(person1.name)  # Python3.11    print(person3.name)  # Python3.11    print(id(person1), id(person3))  # 2989265330704 2989265330704
    person2 = Person2('Cramer')    print(id(person2))  # 2989264763984    print(person2.alias)  # Cramer    print(person1.name)  # Python3.11

通过执行结果我们可以看出:一个类永远只允许一个实例化对象,不管多少个进行实例化,都返回第一个实例化的对象

上面的SingletonObject我们也可以使用下面的实现方式,通过定义一个类内部成员变量_instance:

class SingletonClass:    _instance = None
    def __new__(cls, *args, **kwargs):        print(f"{settings.AGE}")        if not cls._instance:            cls._instance = super(SingletonClass, cls)        return cls._instance

在上面的示例中,我们修改了类的__new__方法,首先检查类的_instance属性是否为None,如果是则创建一个新的实例并赋值给_instance属性,然后返回该实例。这样,每次创建对象时都会返回同一个实例。

使用类装饰器实现单例模式的优点是可以动态创建实例,并且能够保证只有一个实例。它的缺点是不支持多线程,如果在多线程环境下同时创建多个实例,可能会出现竞争条件。

总结

单例模式是一种常用的设计模式,它用于确保一个类只有一个实例,并提供一个全局访问点来访问该实例。在Python中,可以使用多种方法来实现单例模式,包括使用模块、装饰器、类装饰器和元类等。每种方法都有其优点和缺点,我们可以根据具体的需求选择合适的方法来实现单例模式。

以上就是关于Python设计模式之单例模式的介绍,希望对你有所帮助!

下一篇我将介绍《Python设计模式之创建型-简单工厂模式(Simple Factory)》。

Python专栏
https://blog.csdn.net/zhouruifu2015/category_5742543

更多精彩,关注我公号,一起学习、成长

图片

CTO Plus

一个有深度和广度的技术圈,技术总结、分享与交流,我们一起学习。 涉及网络安全、C/C++、Python、Go、大前端、云原生、SRE、SDL、DevSecOps、数据库、中间件、FPGA、架构设计等大厂技术。 每天早上8点10分准时发文。

306篇原创内容

公众号

标准库系列-推荐阅读:

  • Python基础之开发必备-标准库(内置模块)汇总详细介绍(持续更新……)

  • Python标准库1. abc类的定义规范模块实践

  • Python标准库44. datetime模块实践

  • Python标准库45. math模块实践

  • Python标准库46. random模块实践

  • Python标准库48. json模块处理JSON数据和JSON文件实践

  • Python标准库87. typing模块实践

  • Python标准库88. 数据库 (sqlite3) 实践

  • Python标准库89. signal模块实践以及与Linux的信号

  • 看这一篇就够了Python的35个关键字的含义、作用、特性以及使用方式详解

推荐阅读:

  • Python基础之开发必备-标准库(内置模块)汇总详细介绍(持续更新……)

  • 看这一篇就够了Python的35个关键字的含义、作用、特性以及使用方式详解

  • Python基础之最新的73个内置函数(1)

  • Python基础之最新的73个内置函数(2)

  • Python基础之最新的73个内置函数(3)

  • Python基础之最新的73个内置函数(4)

  • Python基础之最新的73个内置函数(5)

  • Python基础之最新的73个内置函数(6)

  • Python基础之最新的73个内置函数(7)

 最后,不少粉丝后台留言问加技术交流群,之前也一直没弄,所以为满足粉丝需求,现建立了一个关于Python相关的技术交流群,加群验证方式必须为本公众号的粉丝,群号如下:

图片

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/223250.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网络安全缓冲区溢出实验

实验要求实验步骤函数 f00()函数 f01()函数 f02() 实验要求 C 程序 homework08.c 的主函数如下: int main(int argc, char * argv[]) { init_buf(Lbuffer, LEN);switch(argc) {case 1: f00(); break;case 2: f01(); break;case 3: f02(); break; default: f00(); …

STM32F407-14.3.13-01发生外部事件时清除 OCxREF 信号

发生外部事件时清除 OCxREF 信号 对于给定通道,在 ETRF⑧ 输入施加高电平(相应 TIMx_CCMRx 寄存器中的 OCxCE⑦ 使能位置“1”),可使 OCxREF⑨ 信号变为低电平。OCxREF⑨ 信号将保持低电平,直到发生下一更新事件 (UEV)…

LT8668SXC HDMI转edp1.4/VBO 最高支持8k60hz

HDMI2.1 Receiver ▪ Compliant with HDMI2.1, HDMI2.0b, HDMI1.4 and DVI1.0 ▪ Data rate up to 8Gbps ▪ Support HDCP 1.4/2.3 ▪ Support HDCP repeater ▪ Support RGB 8/10/12 bpc, YCbCr4:4:4/ YCbCr4:2:2/ YCbCr4:2:0 /8/10/12 bpc ▪ Support up to 8K3…

【电路笔记】-电位差

电位差 文章目录 电位差1、概述2、电位差示例13、分压网络4、电位差示例2 电路中任意两点之间的电压差称为电位差,正是这种电位差使电流流动。 1、概述 与以电荷形式围绕闭合电路流动的电流不同,施加的电势差不会移动或流动。 两点之间产生的电势差的单…

生成测试数据的4种方法、5种工具介绍

在软件测试中,测试数据是测试用例的基础,对测试结果的准确性和全面性有着至关重要的影响。 因此,在进行软件测试时,需要生成测试数据以满足测试场景和要求。本文将介绍什么情况下需要生成测试数据,如何生成测试数据&a…

MOS管加三个元件就组成BUCK电路,为何说难点在于电感?

只要是电子产品就需要供电,就离不开电源,那什么是电源:小到手表中的电子,遥控器的电源,大到220V家庭用电,都可以看做是电源。然而在我们的电路设计中,会用到各种芯片,各种芯片所需要…

【算法问题】N 皇后问题

目录 1.问题定义2.思路分析2.1.基于数组的回溯2.2.基于集合的回溯2.3.基于位运算的回溯 3.代码实现 (Java)3.1.基于数组的回溯3.2.基于数组的回溯3.3.基于位运算的回溯 4.扩展 参考:52.N 皇后 II 1.问题定义 (1)在国际象棋的规则中&#xff…

操作教程|JumpServer搭载RD Client App,让你的移动办公更轻松

随着信息技术的普及和发展,移动办公逐渐成为新的时代趋势。移动办公又被称为3A办公,即办公人员可在任何时间(Anytime)、任何地点 (Anywhere)处理与业务相关的任何事情(Anything)。 …

2024年软件测试面试八股文

前言 (第一个就刷掉一大批人) 有很多“会自动化”的同学来咨询技术问题,他总会问到我一些元素定位的问题。元素定位其实都不算自动化面试的问题。 一般我都会问:你是定位不到吗?通常结果都是说确实定位不到。 做自…

本地启动tomcat,打印的日志中中文乱码

修改配置文件 /conf/logging.properties 修改配置项 java.util.logging.ConsoleHandler.encoding 从UTF-8改成GBK

solidity案例详解(六)服务评价合约

有服务提供商和用户两类实体,其中服务提供商部署合约,默认诚信为true,用户负责使用智能合约接受服务及评价,服务提供商的评价信息存储在一个映射中,可以根据服务提 供商的地址来查找评价信息。用户评价信息&#xff0c…

今天刷basic

一 在kali里边链接这个服务器 ssh -p 25199 rootnode4.buuoj.cn 然后回车 yes 输入密码123456 ls查看发现什么都没有,cd ..返回上一级目录 ls 发现有flag.txt 查看文件得到flag flag{477f20d3-acd3-46e1-b50a-633e58b769c7}

【Vue3从入门到项目实现】RuoYi-Vue3若依框架前端学习——登录页面

若依官方的前后端分离版中,前端用的Vue2,这个有人改了Vue3的前端出来。刚好用来学习: https://gitee.com/weifengze/RuoYi-Vue3 运行前后端项目 首先运行项目 启动前端,npm install、npm run dev 启动后端,按教程配置…

35亿元!开源类ChatGPT平台Mistral AI,再获巨额融资

12月6日,彭博消息,开源类ChatGPT平台Mistral AI获得4.5亿欧元(近35亿元)融资,估值近20亿美元(142亿元)。本次由英伟达、 Salesforce等投资。 Mistral AI的开源大语言模型Mistral 7B主打参数小、…

Apache Doris 详细教程(一)

1、Doris简介 1.1、doris概述 Apache Doris 由百度大数据部研发(之前叫百度 Palo,2018 年贡献到 Apache 社区后, 更名为 Doris ),在百度内部,有超过 200 个产品线在使用,部署机器超过 1000 台…

PIKA,一个神奇的AI工具

随着人工智能技术的不断发展,越来越多的创新性工具开始涌现,为各行各业带来了巨大的变革。其中,视频生成AI工具PIKA,以其独特的功能和广泛的应用领域,吸引了众多用户的关注。本文将详细介绍PIKA的功能、特点以及应用前…

学习设计模式的网站

Refactoring and Design Patternshttps://refactoring.guru/

前端CSS(层叠样式表)总结

CSS2总结 一、CSS基础 1. CSS简介 CSS 的全称为:层叠样式表 ( Cascading Style Sheets ) 。CSS 也是一种标记语言,用于给 HTML 结构设置样式,例如:文字大小、颜色、元素宽高等等。 简单理解: CSS 可以美化…

运维之远程桌面连接失败问题排查

背景:同一局域网,可以ping通但是远程连接不上,排查一下问题。 1、被远程计算机是否允许远程连接 2、被远程计算机防火墙是否允许 3、被远程计算机远程桌面服务是否正常 4、查看用户权限

openGauss学习笔记-145 openGauss 数据库运维-备份与恢复-备份与恢复概述

文章目录 openGauss学习笔记-145 openGauss 数据库运维-备份与恢复-备份与恢复概述145.1 逻辑备份与恢复145.2 物理备份与恢复145.3 闪回恢复145.4 三种备份恢复类型对比145.5 备份方案与策略 openGauss学习笔记-145 openGauss 数据库运维-备份与恢复-备份与恢复概述 数据备份…