前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >python设计模式-单例模式

python设计模式-单例模式

作者头像
goodspeed
发布于 2020-12-22 06:18:27
发布于 2020-12-22 06:18:27
55800
代码可运行
举报
文章被收录于专栏:厉害了程序员厉害了程序员
运行总次数:0
代码可运行

问题:现代化的巧克力工厂具备计算机控制的巧克力锅炉。锅炉做的事情就是把巧克力和牛奶融在一起,然后送到下一个阶段,以制成巧克力棒。下边是一个巧克力公司锅炉控制器的代码,仔细观察一下,这段代码有什么问题?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class ChocolateBoiler(object):

    def __init__(self):
        self.empty = True
        self.boiled = False

    def fill(self):
        # 向锅炉填充巧克力和牛奶混合物
        # 在锅炉内填充原料时,锅炉必须是空的。
        # 一旦填入原料,就要把empty 和 boiled 标志设置好
        if self.empty:
            self.empty = False
            self.boiled = False

    def drain(self):
        # 排出煮沸的巧克力和牛奶
        # 锅炉排出时,必须是满的且煮沸的。
        # 排出完毕empty 设置为 true
        if not self.empty and self.boiled:
            self.empty = True

    def boil(self):
        # 将颅内物煮沸
        # 煮混合物时,锅炉内必须是满的且没有煮沸过
        # 一旦煮沸,就把 boiled 设置为 true
        if not self.empty and not self.boiled:
            self.boiled = True

从代码可以看出,他们加入了多种判断,以防止不好的事情发生。如果同时存在两个ChocolateBoiler实例,那这么多判断岂不是失去作用了。那我们改如何实现这个需求呢?这个问题的核心是,我们要先判断实例是不是已经存在,如果存在就不再创建。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
_chocolate_boiler_instance = None  # 声明实例

def chocolate_boiler():
    global _chocolate_boiler_instance  # 使用全局变量

    if _chocolate_boiler_instance is not None: # 判断是否存在,如果存在,直接返回
        return _chocolate_boiler_instance
    else:
        # 如果不存在,创建一个新的
        _chocolate_boiler_instance = ChocolateBoiler()
        return _chocolate_boiler_instance

现在我们需要获取 ChocolateBoiler 实例的时候只需要调用 chocolate_boiler 方法获取实例即可保证同时只有一个 ChocolateBoiler实例。

这种保证 ChocolateBoiler类只有一个实例,并提供一个全局访问点的模式,就是单例模式

单例模式

定义

单例模式:确保一个类只有一个实例,并提供一个全局访问点。

  • 也就是说,我们使用单例模式要把某个类设计成自己管理的一个单独实例,同时也避免其他类再自行产生实例。并且只允许通过单例类获取单例的实例。
  • 我们也提供对这个实例的全局访问点:当你需要实例时,像类查询,它会返回单个实例。

实现

python 实现单例模式有多种方案:

使用 metaclass

《python cookbook》提供了非常易用的 Singleton 类,只要继承它,就会成为单例。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# python 3 代码实现
class Singleton(type):

    def __init__(self, *args, **kwargs):
        self.__instance = None
        super().__init__(*args, **kwargs)

    def __call__(self, *args, **kwargs):
        if self.__instance is None:
            # 如果 __instance 不存在,创建新的实例
            self.__instance = super().__call__(*args, **kwargs)
            return self.__instance
        else:
            # 如果存在,直接返回
            return self.__instance


class Spam(metaclass=Singleton):

    def __init__(self):
        print('Creating Spam')

a = Spam()
b = Spam()

print(a is b)  # 这里输出为 True

元类(metaclass)可以控制类的创建过程,它主要做三件事:

  • 拦截类的创建
  • 修改类的定义
  • 返回修改后的类

例子中我们构造了一个Singleton元类,并使用__call__方法使其能够模拟函数的行为。构造类 Spam 时,将其元类设为Singleton,那么创建类对象 Spam 时,行为发生如下:

Spam = Singleton(name,bases,class_dict),Spam 其实为Singleton类的一个实例。

创建 Spam 的实例时,Spam()=Singleton(name,bases,class_dict)()=Singleton(name,bases,class_dict).__call__(),这样就将 Spam 的所有实例都指向了 Spam 的属性 __instance上。

使用 __new__

我们可以使用 __new__ 来控制实例的创建过程,代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Singleton(object):

    __instance = None

    def __new__(cls, *args, **kw):
        if not cls.__instance:
            cls.__instance = super().__new__(cls, *args, **kw)
        return cls.__instance

class Foo(Singleton):
    a = 1

one = Foo()
two = Foo()
assert one == two
assert one is two
assert id(one) == id(two)

通过 __new__ 方法,将类的实例在创建的时候绑定到类属性 __instance 上。如果cls.__instance 为None,说明类还未实例化,实例化并将实例绑定到cls.__instance 以后每次实例化的时候都返回第一次实例化创建的实例。注意从Singleton派生子类的时候,不要重载__new__。

使用装饰器
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import functools

def singleton(cls):
    ''' Use class as singleton. '''
    # 首先将 __new__ 方法赋值给 __new_original__
    cls.__new_original__ = cls.__new__

    @functools.wraps(cls.__new__)
    def singleton_new(cls, *args, **kw):
        # 尝试从 __dict__ 取 __it__
        it =  cls.__dict__.get('__it__')
        if it is not None: # 如果有值,说明实例已经创建,返回实例
            return it
        # 如果实例不存在,使用 __new_original__ 创建实例,并将实例赋值给 __it__
        cls.__it__ = it = cls.__new_original__(cls, *args, **kw)
        it.__init_original__(*args, **kw)
        return it
    # class 将原有__new__ 方法用 singleton_new 替换
    cls.__new__ = singleton_new
    cls.__init_original__ = cls.__init__
    cls.__init__ = object.__init__

    return cls

#
# 使用示例
#
@singleton
class Foo:
    def __new__(cls):
        cls.x = 10
        return object.__new__(cls)

    def __init__(self):
        assert self.x == 10
        self.x = 15


assert Foo().x == 15
Foo().x = 20
assert Foo().x == 20

这种方法的内部实现和使用 __new__ 类似:

  • 首先,将 __new__ 方法赋值给 __new_original__,原有 __new__ 方法用 singleton_new 替换,定义 __init_original__ 并将 cls.__init__ 赋值给 __init_original__
  • 在 singleton_new 方法内部,尝试从 __dict__ 取 __it__(实例)
  • 如果实例不存在,使用 __new_original__ 创建实例,并将实例赋值给 __it__,然后返回实例
最简单的方式

将名字singleton绑定到实例上,singleton就是它自己类的唯一对象了。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class singleton(object):
    pass
singleton = singleton()

https://github.com/gusibi/Metis/blob/master/apis/v1/schemas.py#L107 使用的就是这种方式,用来获取全局的 request

Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。

参考链接

  • Creating a singleton in Python
  • Python单例模式
  • Why is __init__() always called after __new__()?

最后,感谢女朋友支持。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-11-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 四月 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
python实现单例模式的5种方法
单例模式最初的定义出现于《设计模式》(艾迪生维斯理, 1994):“保证一个类仅有一个实例,并提供一个访问它的全局访问点。”
Tim在路上
2020/08/04
6.3K0
【python设计模式-创建型】单例模式
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
西西嘛呦
2020/08/26
3890
【python设计模式-创建型】单例模式
python3实现单例模式
1、通过模块调用 2、使用__new__方法 3、使用装饰器 4、使用元类(metaclass)
py3study
2020/01/03
3K0
python设计模式之单例模式
简单理解:单例即为单个实例,也就是每次实例化创建对象时获得的都是同一个对象,当然同一个对象的属性都是相同的,方法也是相同的,地址也是相同的,这样给我们带来的好处就是可以避免消耗过多的内存或CPU资源,例如数据库类,我们希望每次都使用同一个数据库对象来对数据库进行操作,以维护数据的一致性。又如模块的导入,如果没有导入该模块,则导入该模块并实例化,如果已经导入,则返回该模块的对象
py3study
2020/01/20
6810
Python实现Singleton模式的
使用python实现设计模式中的单例模式。单例模式是一种比较常用的设计模式,其实现和使用场景判定都是相对容易的。本文将简要介绍一下python中实现单例模式的几种常见方式和原理。一方面可以加深对python的理解,另一方面可以更加深入的了解该模式,以便实际工作中能更加灵活的使用单例设计模式。
py3study
2020/01/19
2.1K0
Python中的单例模式的几种实现方式的及优化
单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。 比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,
用户1214487
2018/01/24
1.2K0
Python设计模式之单例模式
  本系列文章是希望将软件项目中最常见的设计模式用通俗易懂的语言来讲解清楚,并通过Python来实现,每个设计模式都是围绕如下三个问题: 为什么?即为什么要使用这个设计模式,在使用这个模式之前存在什么样的问题? 是什么?通过Python语言来去实现这个设计模式,用于解决为什么中提到的问题。 怎么用?理解了为什么我们也就基本了解了什么情况下使用这个模式,不过在这里还是会细化使用场景,阐述模式的局限和优缺点。   这一篇我们先来看看单例模式。单例模式是设计模式中逻辑最简单,最容易理解的一个模式,简单到只需要一句
Jetpropelledsnake21
2018/05/03
1.1K0
Python学习笔记:单例模式
单例模式:一个类无论实例化多少次,返回的都是同一个实例,例如:a1=A(), a2=A(), a3=A(),a1、a2和a3其实都是同一个对象,即print(a1 is a2)和print(a2 is a3)都会打印True。
py3study
2020/01/19
5620
单例模式
如果想使得某个类从始至终最多只有一个实例,使用new方法会很简单。Python中类是通过new来创建实例的:
用户2936342
2018/08/27
4160
python 单例模式
单例模式 多次实例化的结果指向同一个实例 单例模式实现方式 方式一: 1 import settings 2 3 class MySQL: 4 __instance = None 5 6 def __init__(self, ip, port): 7 self.ip = ip 8 self.port = port 9 10 @classmethod 11 def from_conf(cls): 12 if
py3study
2020/01/19
4700
在Python中实现单例模式
有些时候你的项目中难免需要一些全局唯一的对象,这些对象大多是一些工具性的东西,在Python中实现单例模式并不是什么难事。以下总结几种方法: 使用类装饰器 使用装饰器实现单例类的时候,类本身并不知道自己是单例的,所以写代码的人可以不care这个,只要正常写自己的类的实现就可以,类的单例有装饰器保证。 def singleton(cls): instancec = {} def _wrapper(*args,**kwargs): if cls not in instance
Jetpropelledsnake21
2018/05/02
1.3K0
20·Python基础-单例模式四种实现方式
-多年互联网运维工作经验,曾负责过大规模集群架构自动化运维管理工作。 -擅长Web集群架构与自动化运维,曾负责国内某大型金融公司运维工作。 -devops项目经理兼DBA。 -开发过一套自动化运维平台(功能如下): 1)整合了各个公有云API,自主创建云主机。 2)ELK自动化收集日志功能。 3)Saltstack自动化运维统一配置管理工具。 4)Git、Jenkins自动化代码上线及自动化测试平台。 5)堡垒机,连接Linux、Windows平台及日志审计。 6)SQL执行及审批流程。 7)慢查询日志分析web界面。
DriverZeng
2022/09/26
2500
20·Python基础-单例模式四种实现方式
元类到底是什么东东?
最近在看Python的面向对象编程,卡在了元类这个知识点,经过各种资料查询和学习,就有了这篇文章,还是那句话,能力时间有限,如果有错误,还望批评指正,谢谢。
罗罗攀
2021/07/21
2880
元类到底是什么东东?
python的单例模式
所谓单例,就是保证一个类仅有一个实例。所有引用(实例、对象)拥有相同的状态(属性)和行为(方法);
py3study
2020/01/08
7060
单利模式的四种方式
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/124468.html原文链接:https://javaforall.cn
全栈程序员站长
2022/07/21
3480
Python单例模式(Singleton)的N种实现
很多初学者喜欢用全局变量,因为这比函数的参数传来传去更容易让人理解。确实在很多场景下用全局变量很方便。不过如果代码规模增大,并且有多个文件的时候,全局变量就会变得比较混乱。你可能不知道在哪个文件中定义了相同类型甚至重名的全局变量,也不知道这个变量在程序的某个地方被做了怎样的操作。
Crossin先生
2018/07/24
6000
python实现单例模式详解
缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。 使用场景:
渔父歌
2019/08/06
1.7K0
Python 元类
印象中,是在创建单例模式时知道可以用到元类(metaclass),但始终对其了解的不是很透彻,很多人也都说元类是Python中较难理解的概念之一,于是找来几本书,希望可以找到答案,本文以Python3为例。
oYabea
2022/01/06
8020
Python 元类
Python 实现单例模式
在面向对象编程中,通过单例模式只能创建一个类实例,也就是一个类永远只有一个实例对象。
Python碎片公众号
2021/02/26
2.2K0
Python 实现单例模式
Python中的单例模式有几种实现方式?
公众号新增加了一个栏目,就是每天给大家解答一道Python常见的面试题,反正每天不贪多,一天一题,正好合适,只希望这个面试栏目,给那些正在准备面试的同学,提供一点点帮助!
程序员小猿
2021/01/19
5390
相关推荐
python实现单例模式的5种方法
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验