zoukankan      html  css  js  c++  java
  • Python实现单例模式

    Python实现单例模式

    单例模式

    介绍
    意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
    主要解决:一个全局使用的类频繁地创建与销毁。
    何时使用:当您想控制实例数目,节省系统资源的时候。
    如何解决:判断系统是否已经有这个单例,如果有则返回,如果没有则创建。
    关键代码:构造函数是私有的。
    应用实例:
    1、一个班级只有一个班主任。
    2、Windows 是多进程多线程的,在操作一个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例来进行。
    3、一些设备管理器常常设计为单例模式,比如一个电脑有两台打印机,在输出的时候就要处理不能两台打印机打印同一个文件。
    优点:
    1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
    2、避免对资源的多重占用(比如写文件操作)。
    缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
    使用场景:
    1、要求生产唯一序列号。
    2、WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
    3、创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。
    

      

    第一种方法

     1 class User(object):
     2     #定义类属性
     3     __instance=None
     4     #初始化方法
     5     def __init__(self,name):
     6         self.name=name
     7 
     8     @classmethod
     9     #定义类方法
    10     def get_instance(cls,name):
    11         #如果__instance为空,则执行
    12         if not cls.__instance:
    13             #实例化对象,并赋值给__instance属性
    14             cls.__instance=User(name)
    15         return cls.__instance
    16 u1 =User.get_instance("lili")
    17 u2 = User.get_instance("lisi")
    18 print(u1==u2)
    19 print(id(u1))
    20 print(id(u2))
    运行结果:
    True 41816192 41816192

      

    代码分析

    # 要实现不管实例化多少次,拿到的都是同一个对象
    # 这里我们通过调用类的静态方法来实例化类(@classmethod)
    # 第一次实例化对象的时候,类属性为空,则会初始化对象,并返回对象
    # 第二次时,类属性已不为空,则不会实例化对象,直接返回第一次生成的对象
    关键点:通过类静态方法实例化对象
         __instance类属性的作用

    补充classmethod

    classmethod 修饰符对应的函数不需要实例化,不需要 self 参数,但第一个参数需要是表示自身类的 cls 参数,可以来调用类的属性,类的方法,实例化对象等。
    View Code

    这里name是否相同?

    # 我们是使用通过调用类的静态方法来实例化对象的,所以这里不会直接执行__init__方法,是在静态方法里间实例化时执行了__init__方法,并且只会执行一次。
    # 这里每次实例化一次对象,拿到的对象是同一个对象,name也相同。

     

    有一个问题?我们知道有两种方法初始化对象,如果我们使用User("lili")来实例化对象会怎样?

    # 第一种:u1=User("lili")  #通过 __init__实例化对象
    # 第二种:u1=get_instance("lili")  #通过类的静态方法间接实例化对象
    

      

    class User(object):
        #定义类属性
        __instance=None
        #初始化方法
        def __init__(self,name):
            self.name=name
    
        @classmethod
        #定义类方法
        def get_instance(cls,name):
            #如果__instance为空,则执行
            if not cls.__instance:
                #实例化对象,并赋值给__instance属性
                cls.__instance=User(name)
            return cls.__instance
    u1 =User("lili")
    u2 = User("lisi")
    print(u1==u2)
    print(id(u1))
    print(id(u2))
    代码
    False
    36376704
    36376760
    

      

    第二种方法

     1 class User(object):
     2     #定义类属性
     3     __instance=None
     4     #初始化方法
     5     def __init__(self,name):
     6         self.name=name
     7     def __new__(cls,name):
     8         #保证object.__new__(cls)方法只会调用第一次
     9         if not cls.__instance:
    10             #object.__new__(cls)创建对象
    11             cls.__instance=object.__new__(cls)
    12         return cls.__instance
    13 u1 = User("lili")
    14 u2 = User("lisi")
    15 print(u1==u2)
    16 print(id(u1))
    17 print(id(u2))
    运行结果:
    True 42106384 42106384

      

    代码分析

    #当代码执行u1 = User("lili")
    # 会运行到__new__方法,此时类属性__instance为空,则会创建对象,把对象赋值给__instance,并返回对象
    # 现在代码还没有运行完,会继续执行__init__方法,会将"lili"赋值给name,现在name="lili"
    # 执行u1 = User("lili"),类属性不为空,不会创建对象,直接返回第一次创建的对象
    #此时是最重要的,def __init__(self,name)中self为第一次的对象,而传进来的name为第二次的name,就会将"lisi"赋值给name,现在name="lisi"
    # 但是对象永远都是那个对象,name却不是那个name了。
    #所以这里每次实例化一次对象,虽然对象还是那个对象,但是name会不一样。

      

  • 相关阅读:
    2021.12.10
    2021.12.6
    12月3日
    《大话软件工程需求分析与软件设计》阅读笔记
    《大话软件工程需求分析与软件设计》阅读笔记
    期末加分申请
    2021.12.8
    2021.12.4
    <20211230>主板故障: Win10休眠后黑屏假死,无法回到桌面
    <20211130>怪异的主板故障开机黑屏,不显示, 黄绿灯频闪故障
  • 原文地址:https://www.cnblogs.com/-wenli/p/10433503.html
Copyright © 2011-2022 走看看