目录
作用
适用场景
使用模块
使用装饰器
使用元类
__new__方法单例模式
总结
更多关于Python的相关技术点,敬请关注公众号:CTO Plus后续的发文,有问题欢迎后台留言交流。
注意:本代码示例环境Python版本使用最新的Python3.11
在前面的文章《关于Python设计模式的一些事情,设计模式是否真能帮你解决什么问题?》中对Python的设计模式进行了一个大体的分享介绍。本篇我将来总结下第一个设计模式,单例模式是一种创建型设计模式,它的目的是确保一个类只有一个实例,并提供一个全局访问点来访问该实例。在Python中,可以使用多种方法来实现单例模式,本文这里我将介绍其中几种常用的方法,包括使用模块、使用装饰器、使用元类、以及__new__方法。
【Python设计模式系列】
-
《关于Python设计模式的一些事情,设计模式是否真能帮你解决什么问题?》
-
《Python设计模式之创建型-单例模式(Singleton)》
-
《Python设计模式之创建型-简单工厂模式(Simple Factory)》
-
《Python设计模式之创建型-工厂方法模式(Factory Method)》
-
《Python设计模式之创建型-抽象工厂模式(Abstract Factory)》
-
《Python设计模式之创建型-创建者(建造者)模式(Builder)》
-
《Python设计模式之创建型-原型模式(Prototype)》
-
《Python设计模式之创建型-对象池模式(Pool)》
-
《Python设计模式之创建型-惰性评价模式(Lazy Evaluation)》
-
《Python设计模式之结构型-代理模式(Proxy)》
-
《Python设计模式之结构型-适配器模式(Adapter)》
-
《Python设计模式之结构型-装饰器模式(Decorator)》
-
《Python设计模式之结构型-组合模式(Composite)》
-
《Python设计模式之结构型-外观模式(Facade)》
-
《Python设计模式之结构型-享元模式(Flyweight)》
-
《Python设计模式之结构型-桥接模式(Bridge)》
-
《Python设计模式之结构型-3层模式(3-tier)》
-
《Python设计模式之结构型-前端控制器模式(front controller)》
-
《Python设计模式之结构型-MVC模式(mvc)》
-
《Python设计模式之行为型-观察者模式(Observer)》
-
《Python设计模式之行为型-模板方法(Template Method)模式》
-
《Python设计模式之行为型-策略模式(Strategy)》
-
《Python设计模式之行为型-职责链模式(Chain of Responsibility)》
-
《Python设计模式之行为型-状态模式(State)》
-
《Python设计模式之行为型-迭代器模式(Iterator)》
-
《Python设计模式之行为型-访问者(访客)模式(Visitor)》
-
《Python设计模式之行为型-命令模式(Command)》
-
《Python设计模式之行为型-解释器模式(Interpreter)》
-
《Python设计模式之行为型-调停者(中介者)模式(Mediator)》
-
《Python设计模式之行为型-备忘录模式(Memento)》
-
《Python设计模式之行为型-目录模式(catalog)》
-
《Python设计模式之行为型-方法链模式(chaining method)》
-
《Python设计模式之行为型-发布订阅模式(publish subscribe)》
-
《Python设计模式之行为型-注册模式(registry)》
-
《Python设计模式之行为型-规格模式(specification)》
作用
确保一个类只有一个实例,并提供一个全局访问点来获取该实例。
适用场景
-
当类只能有一个实例而且客户可以从一个众所周知的访问点(如全局变量、或一个全局配置)访问它时,例如数据库连接、日志记录等。
-
当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。
使用模块
在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
@singleton
class 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相关的技术交流群,加群验证方式必须为本公众号的粉丝,群号如下: