python的单例模式

单例模式(Singleton Pattern),是一种软件设计模式,是类只能实例化一个对象,

    目的是便于外界的访问,节约系统资源,如果希望系统中 只有一个对象可以访问,就用单例模式,

    显然单例模式的要点有三个;一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。

在 Python 中,我们可以用多种方法来实现单例模式:

  • 使用模块
  • 使用 __new__
  • 使用装饰器(decorator)
  • 使用元类(metaclass)

概念

简单说,单例模式(也叫单件模式)的作用就是保证在整个应用程序的生命周期中,任何一个时刻,单例类的实例都只存在一个(当然也可以不存在)

 

例子:

一台计算机上可以连好几个打印机,但是这个计算机上的打印程序只能有一个,这里就可以通过单例模式来避免两个打印作业同时输出到打印机中,即在整个的打印过程中我只有一个打印程序的实例。

 

super(B, self).__init__()是这样理解的:super(B, self)首先找到B的父类(就是类A),然后把类B的对象self转换为类A的对象(通过某种方式,一直没有考究是什么方式,惭愧),然后“被转换”的类A对象调用自己的__init__函数。考虑到super中只有指明子类的机制,因此,在多继承的类定义中,通常我们保留使用类似代码段1的方法。

  1. super并不是一个函数,是一个类名,形如super(B, self)事实上调用了super类的初始化函数,
       产生了一个super对象;
  2. super类的初始化函数并没有做什么特殊的操作,只是简单记录了类类型和具体实例;
  3. super(B, self).func的调用并不是用于调用当前类的父类的func函数;
  4. Python的多继承类是通过mro的方式来保证各个父类的函数被逐一调用,而且保证每个父类函数
       只调用一次(如果每个类都使用super);
  5. 混用super类和非绑定的函数是一个危险行为,这可能导致应该调用的父类函数没有调用或者一
       个父类函数被调用多次。

__new__: 对象的创建,是一个静态方法,第一个参数是cls。(想想也是,不可能是self,对象还没创建,哪来的self)
__init__ : 对象的初始化, 是一个实例方法,第一个参数是self。

 

__new__方法在类定义中不是必须写的,如果没定义,默认会调用object.__new__去创建一个对象。如果定义了,就是override,可以custom创建对象的行为。
聪明的读者可能想到,既然__new__可以custom对象的创建,那我在这里做一下手脚,每次创建对象都返回同一个,那不就是单例模式了吗?没错,就是这样。可以观摩《飘逸的python - 单例模式乱弹》
定义单例模式时,因为自定义的__new__重载了父类的__new__,所以要自己显式调用父类的__new__,即object.__new__(cls, *args, **kwargs),或者用super()。,不然就不是extend原来的实例了,而是替换原来的实例。

 

 

代码

import threading

 

class Signleton(object):

    def __init__(self):

        print("__init__ method called")

 

    def __new__(cls):

        print("__new__ method called")

        mutex=threading.Lock()

        mutex.acquire() # 上锁,防止多线程下出问题

        if not hasattr(cls, 'instance'):

            cls.instance = super(LogSignleton, cls).__new__(cls)

        mutex.release()

        return cls.instance

 

if __name__ == '__main__':

obj = Signleton()

 

输出结果:

>>> ================================ RESTART ================================

>>>

__new__ method called

__init__ method called

>>> 

 

说明

1.从输出结果来看,最先调用 __new__ 方法,然后调用__init__方法

2. __new__ 通常用于控制生成一个新实例的过程,它是类级别的方法。

3. __init__ 通常用于初始化一个新实例,控制这个初始化的过程,比如添加一些属性,做一些额外的操作,发生在类实例被创建完以后。它是实例级别的方法。

 

 

 

方法1;

  __new__ 在__init__初始化前,就已经实例化对象,可以利用这个方法实现单例模式。

    1. print '----------------------方法1--------------------------'  
    2. #方法1,实现__new__方法  
    3. #并在将一个类的实例绑定到类变量_instance上,  
    4. #如果cls._instance为None说明该类还没有实例化过,实例化该类,并返回  
    5. #如果cls._instance不为None,直接返回cls._instance  
    6. class Singleton(object):  
    7.     def __new__(cls, *args, **kw):  
    8.         if not hasattr(cls, '_instance'):  
    9.             orig = super(Singleton, cls)  
    10.             cls._instance = orig.__new__(cls, *args, **kw)  
    11.         return cls._instance  
    12.   
    13. class MyClass(Singleton):  
    14.     a = 1  
    15.   
    16. one = MyClass()  
    17. two = MyClass()  
    18.   
    19. two.a = 3  
    20. print one.a  
    21. #3  
    22. #one和two完全相同,可以用id(), ==, is检测  
    23. print id(one)  
    24. #29097904  
    25. print id(two)  
    26. #29097904  
    27. print one == two  
    28. #True  
    29. print one is two  
    30. #True 
      1. print '----------------------方法2--------------------------'  
      2. #方法2,共享属性;所谓单例就是所有引用(实例、对象)拥有相同的状态(属性)和行为(方法)  
      3. #同一个类的所有实例天然拥有相同的行为(方法),  
      4. #只需要保证同一个类的所有实例具有相同的状态(属性)即可  
      5. #所有实例共享属性的最简单最直接的方法就是__dict__属性指向(引用)同一个字典(dict)  
      6. #可参看:http://code.activestate.com/recipes/66531/  
      7. class Borg(object):  
      8.     _state = {}  
      9.     def __new__(cls, *args, **kw):  
      10.         ob = super(Borg, cls).__new__(cls, *args, **kw)  
      11.         ob.__dict__ = cls._state  
      12.         return ob  
      13.   
      14. class MyClass2(Borg):  
      15.     a = 1  
      16.   
      17. one = MyClass2()  
      18. two = MyClass2()  
      19.   
      20. #one和two是两个不同的对象,id, ==, is对比结果可看出  
      21. two.a = 3  
      22. print one.a  
      23. #3  
      24. print id(one)  
      25. #28873680  
      26. print id(two)  
      27. #28873712  
      28. print one == two  
      29. #False  
      30. print one is two  
      31. #False  
      32. #但是one和two具有相同的(同一个__dict__属性),见:  
      33. print id(one.__dict__)  
      34. #30104000  
      35. print id(two.__dict__)  
      36. #30104000  
      37.   
      38. print '----------------------方法3--------------------------'  
      39. #方法3:本质上是方法1的升级(或者说高级)版  
      40. #使用__metaclass__(元类)的高级python用法  
      41. class Singleton2(type):  
      42.     def __init__(cls, name, bases, dict):  
      43.         super(Singleton2, cls).__init__(name, bases, dict)  
      44.         cls._instance = None  
      45.     def __call__(cls, *args, **kw):  
      46.         if cls._instance is None:  
      47.             cls._instance = super(Singleton2, cls).__call__(*args, **kw)  
      48.         return cls._instance  
      49.   
      50. class MyClass3(object):  
      51.     __metaclass__ = Singleton2  
      52.   
      53. one = MyClass3()  
      54. two = MyClass3()  
      55.   
      56. two.a = 3  
      57. print one.a  
      58. #3  
      59. print id(one)  
      60. #31495472  
      61. print id(two)  
      62. #31495472  
      63. print one == two  
      64. #True  
      65. print one is two  
      66. #True  
      67.   
      68. print '----------------------方法4--------------------------'  
      69. #方法4:也是方法1的升级(高级)版本,  
      70. #使用装饰器(decorator),  
      71. #这是一种更pythonic,更elegant的方法,  
      72. #单例类本身根本不知道自己是单例的,因为他本身(自己的代码)并不是单例的  
      73. def singleton(cls, *args, **kw):  
      74.     instances = {}  
      75.     def _singleton():  
      76.         if cls not in instances:  
      77.             instances[cls] = cls(*args, **kw)  
      78.         return instances[cls]  
      79.     return _singleton  
      80.  
      81. @singleton  
      82. class MyClass4(object):  
      83.     a = 1  
      84.     def __init__(self, x=0):  
      85.         self.x = x  
      86.   
      87. one = MyClass4()  
      88. two = MyClass4()  
      89.   
      90. two.a = 3  
      91. print one.a  
      92. #3  
      93. print id(one)  
      94. #29660784  
      95. print id(two)  
      96. #29660784  
      97. print one == two  
      98. #True  
      99. print one is two  
      100. #True  
      101. one.x = 1  
      102. print one.x  
      103. #1  
      104. print two.x

        ==========================================================

          1. 单例模式

            单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。

            比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象。

            在 Python 中,我们可以用多种方法来实现单例模式:

            • 使用模块
            • 使用 __new__
            • 使用装饰器(decorator)
            • 使用元类(metaclass)

            使用模块

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

            将上面的代码保存在文件 mysingleton.py 中,然后这样使用:

            使用 __new__

            为了使类只能出现一个实例,我们可以使用 __new__ 来控制实例的创建过程,代码如下:

            在上面的代码中,我们将类的实例和一个类变量 _instance 关联起来,如果 cls._instance 为 None 则创建实例,否则直接返回 cls._instance

            执行情况如下:

            使用装饰器

            我们知道,装饰器(decorator)可以动态地修改一个类或函数的功能。这里,我们也可以使用装饰器来装饰某个类,使其只能生成一个实例,代码如下:

            在上面,我们定义了一个装饰器 singleton,它返回了一个内部函数 getinstance,该函数会判断某个类是否在字典 instances 中,如果不存在,则会将 cls 作为 key,cls(*args, **kw) 作为 value 存到 instances 中,否则,直接返回 instances[cls]

            使用 metaclass

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

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

            使用元类实现单例模式的代码如下:

            class Singleton(type): _instances = {} def __call__(cls, *args, **kwargs): if cls not in cls._instances: cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) return cls._instances[cls] # Python2 class MyClass(object): __metaclass__ = Singleton # Python3 # class MyClass(metaclass=Singleton): # pass
            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            class Singleton(type):
                _instances = {}
                def __call__(cls, *args, **kwargs):
                    if cls not in cls._instances:
                        cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
                    return cls._instances[cls]
            # Python2
            class MyClass(object):
                __metaclass__ = Singleton
            # Python3
            # class MyClass(metaclass=Singleton):
            #    pass

转载于:https://www.cnblogs.com/gyh04541/p/7853652.html

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c语言自定义输出小数点位数_C语言中输出时怎样控制小数点后的位数,请举例说明......

控制2113小数位数就是通过输出格式说明符来规定的举例5261说明如下4102:1、float f13.1415926;2、float f21234.1415926;3、float f3124.1;4、printf("%3.4f",f1);//输出结果为:_ _ 3.1416(_表示空格1653)5、printf("%3.4f",f2);//输…

语言求圆周率近似值改错_新证明解决了如何求无理数的近似值

原文:Kevin Hartnett,QuantaMagazine日前,一份新鲜出炉的论文证明了近80年悬而未决的达芬-谢弗(Duffin-Schaeffer)猜想,让数轴上讳莫如深的部分再也不如表面看来那么遥不可及。达芬-谢弗猜想的证明完美解答…

python在不同层级目录import模块的方法

转自:https://www.cnblogs.com/luoye00/p/5223543.html 使用python进行程序编写时,经常会使用第三方模块包。这种包我们可以通过python setup install 进行安装后,通过import XXX或from XXX import yyy 进行导入。不过如果是自己遍写的依赖包…

谷歌翻译无法连接网络_window10无法连接网络

很多朋友都将电脑的系统升级到Win10,如果遇到了Win10系统无法连接网络该如何解决,下面就为大家介绍一下解决的方法。window10无法连接网络一、检查路由器1、重新启动(断电10秒钟) 无线路由器和猫(调制解调器),有时候是路由器的故障&#xff1…

php: +1天, +3个月, strtotime(): +1 day, +3 month

php: 1天, 3个月, strtotime(): 1 day, 3 month 比如,我现在当前时间基础上1天: strtotime("1 day"); 比如我现在,2014-05-01时间上 3个月 $s strtotime("2014-05-01"); $d strtotime("3 month", $s); 转载…

获取弹出的窗口_Win7系统如何获取设置everyone权限的问题

一位win7之家系统的小伙伴,想要在电脑系统中获取everyone权限,但是不知道该怎么做,对于Win7电脑如何获取设置everyone权限这个问题,小编觉得我们可以在电脑的计算机中找到相关的磁盘,打开磁盘属性然后在安全选项中进行…

异步请求中jetty处理ServletRequestListener的坑

标题起得比较诡异,其实并不是坑,而是jetty似乎压根就没做对异步request的ServletRequestListener的特殊处理,如果文中有错误欢迎提出,可能自己有所疏漏了。 之前遇到了一个bug,在Listener中重写requestDestroyed清理资…

Maven国内镜像 Maven阿里云镜像

<mirror><id>nexus-aliyun</id><mirrorOf>central</mirrorOf><name>Nexus aliyun</name><url>http://maven.aliyun.com/nexus/content/groups/public</url> </mirror> 转载于:https://www.cnblogs.com/a2b1/p/787…

华为h22h05服务器做raid_华为V5服务器 RAID控制卡(LSI SAS3008IR)

提供高速接口和模块LSI SAS3008IR的PCIe Core提供PCIe x8接口&#xff0c;每lane速率为8Gb/s&#xff0c;可以兼容x1、x2、x4配置&#xff1b;支持PCIe 3.0规格&#xff0c;兼容PCIe 2.x和PCIe 1.x。LSI SAS3008IR的SAS模块提供SAS功能&#xff0c;并定义支持的硬盘速率。LSI S…

通过tomcat日志定位错误

1、tomcat的安装路径下tomcat home下的common文件夹下的classes文件夹中创建log4j.properties文件&#xff0c;即 apache-tomcat-5.5.20\common\classes log4j.rootLoggerinfo,Console,Rlog4j.appender.Consoleorg.apache.log4j.ConsoleAppenderlog4j.appender.Console.layouto…

css加了固定定位就不显示内容_前端开发必备,学好”定位“向菜鸟说拜拜

众所周知&#xff0c;前端CSS中&#xff0c;盒模型、浮动、定位为必须掌握的三座大山。今天就来聊聊定位的那些事。定位是什么&#xff1f;先来看看哪些场景用到定位&#xff0c;如下图所示&#xff0c;凡是有盒子压住另一个盒子的地方都可定位&#xff0c;因为用浮动做不了&am…

vscode更换主题的插件_VScode 插件开发(三)主题

咱们上回书说道&#xff0c;安装完基础环境&#xff0c;我们要来玩自己的主题了1. 创建一个主题项目$ yo code选中 New Color Theme接下来照图中所选&#xff0c;完成项目创建(简单英语不做解释)打开项目如图2. 配置文件2.1 themes这个文件夹包含主题配置文件&#xff0c;可以新…

sql之引擎介绍

数据库引擎介绍MySQL数据库引擎取决于MySQL在安装的时候是如何被编译的。要添加一个新的引擎&#xff0c;就必须重新编译MYSQL。在缺省情况下&#xff0c;MYSQL支持三个引擎&#xff1a;ISAM、MYISAM和HEAP。另外两种类型INNODB和BERKLEY&#xff08;BDB&#xff09;&#xff0…

jquery查找ul属性不是hide,jQuery的ul显示/隐藏功能

Im trying to hide my divs which will have content in them when finished. I have a jsFiddle file and some of the coding is not complete, just wrote it very fast to give you an idea.I believe that the ul is making it not be created correctly.解决方案The html…

HttpContext

相关知识点&#xff1a;ttp://www.cnblogs.com/wujy/p/3264475.htmlHttpContext context HttpContext.Current; if( context ! null ) {// 在这里访问与请求有关的东西。 } 记录当前用户信息的线程当前线程是指与【当前请求】相关的线程。在ASP.NET中&#xff0c;有些线程并非…

mysql if 多个_MySQL使用IF语句CONCAT多个字段

语法不正确.你想使用CASE&#xff1a;SET loc_name Location;SET add_street Add Street;SET add_number 10;SET x_street_1 Street 1;SET x_street_2 Street 2;SET city City;SET state State;SET country Country;SELECT Concat(loc_name, \n, CASEWHEN add_number !…

IOS+Android马甲包封装上架!

目的 我们有自己的一个主网站平台&#xff0c;为了推广我们的主网站平台&#xff0c;我们需要长期制作大量马甲app&#xff0c;然后引导用户到我们的主网站游戏&#xff0c;所以&#xff0c;你制作的app的功能只给审核人员看到&#xff0c;只是为了应付审核&#xff0c;app上架…

软件工程概论课后作业01

1. 网站系统开发需要掌握的技术 ①java语言 Java语言体系比较庞大&#xff0c;包括多个模块。从WEB项目应用角度讲有JSP&#xff0c;Servlet&#xff0c;JDBC&#xff0c;JavaBean&#xff08;Application&#xff09;四部分技术。JDBC可做三件事情&#xff1a;与数据库建立连接…

mysql low_case_MySQL8.0的坑之lower_case_table_names

在安装了8.0.14之后&#xff0c;初始化的时候在my.cnf里设置了lower_case_table_names1&#xff0c;安装好了之后&#xff0c;启动报错&#xff1a;2019-01-28T13:24:24.91946308:00 0 [System] [MY-010116] [Server] /usr/local/mysql/bin/mysqld (mysqld 8.0.14) starting as…

php5.4 mysql connect_php5.4 Call to undefined function mysql_connect()

今天学习PHP中连接MySQL&#xff0c;使用mysql_connect()函数时&#xff0c;碰到以下错误&#xff1a;“Call to undefined function mysql_connect()”&#xff0c;PHP版本&#xff1a;5.4.29MySQL版本&#xff1a;5.5.28Apache版本&#xff1a;2.2.22解决方法如下&#xff1a…