zoukankan      html  css  js  c++  java
  • Python 单例模式(3种方式)

    Python 单例模式(3种方式)

    方式一:

    复制代码
    # 单例模式:
    #     实现目的:实例化多次,得到的实例是同一个,就是同一个对象,同一个名称空间(更加节省空间)
    
    ####################################方式一:在类内部定义一个类方法#################################
    import settings
    
    class Mysql:
        __instance=None         #定义一个变量,来接收实例化对象,方便下面做判断
        def __init__(self,ip,port):
            self.ip=ip
            self.port=port
    
    #
        @classmethod #做成类方法   #绑定给Mysql类去直接调用实例化
        def from_conf(cls):
            #目的是要调取mysql这个类通过从配置文件读取IP、端口参数,完成调用init方法,拿到一个实例化init方法的对象
            # mysql(settings.IP,settings.PORT)
    
            #如果是这样每次,实例化出的对象,都是不同的名称空间,但是数据是同一份
            # return cls(settings.IP,settings.PORT)  #cls(ip,port)  就是调用init方法
    
            #演变最终版:思考可以统一定义一个初始变量__instance=None,将第一次实例的对象传给他,有每次外面再访问就直接
            if cls.__instance is None:
                cls.__instance=cls(settings.IP,settings.PORT)
            return cls.__instance
    
    #之前版本:
    # p1=Mysql.from_conf()
    # print(p1)   #<__main__.Mysql object at 0x02BE82B0> #数据是同一份,但每次实例化,指向的都是不同的内存地址
    # p2=Mysql.from_conf()
    # print(p2)  #<__main__.Mysql object at 0x02C1AB90>
    
    
    #这样写就完美的实现了隔离:
    #升级版本后,可以实现,访问存的东西一样的,可以指向同一个内存空间
    obj=Mysql.from_conf()
    print(obj.__dict__)
    
    #也可以传入新的参数,另外新造一个名称空间
    obj2=Mysql('3.3.3.3',8888)
    print(obj2.__dict__)
    复制代码

    方式二:

    复制代码
    #方式二:装饰器
    import settings
    
    def singleton(cls):
        __instance=cls(settings.IP,settings.PORT)     #给Mysql的init方法传参,实例化得到一个对象,__instance
        def wrapper(*args,**kwargs):       #判断外面调用时,是否有传值进来
            if len(args) == 0 and len(kwargs)== 0:
                return __instance              #用户没有传传参,意思直接返回默认settings的值
            return cls(*args,**kwargs)     #否则会创建新的值
        return wrapper
    
    @singleton
    class Mysql:    ##Mysql=singleton(Mysql)  #Mysql=wrapper
        def __init__(self,ip,port):
            self.ip=ip
            self.port=port
        def aa(self):
            print('IP地址:%s 端口:%s'%(self.ip,self.port))
    
    #实现的结果是:想要实现的是mysql不传参数,默认指向同一个实例
    #没有传参数的调用:保证每次实例化得到的是同一个内存地址
    obj1=Mysql() #wrapper()
    obj2=Mysql() #wrapper()
    print(obj1.__dict__,id(obj))  #{'ip': '1.1.1.1', 'port': 3306} 45554896
    print(obj2.__dict__,id(obj))  #{'ip': '1.1.1.1', 'port': 3306} 45554896
    #有传参的情况下,创建新的
    obj2=Mysql('2.2.2.2',666)
    print(obj2.__dict__)
    复制代码

    方式三:

    复制代码
    方式三:自定义元类
    #自定义元类控制类的调用过程,即类的实例化:__call__
    import settings
    class Mymeta(type):  #init在定义类时就已经建好了
        def __init__(self,class_name,class_bases,class_dic):   #造Mysql空对象,调类中init方法,继承父类,造一个空对象
            super(Mymeta,self).__init__(class_name,class_bases,class_dic)
    
            # obj=self.__new__(self) #造出一个mysql的空对象
            #         # self.__init__(obj,settings.IP,settings.PORT) #w从配置文件中加载配置完成Mysql对象的初始化
            #         # self.__instance=obj  #赋值操作
         #
            self.__instance=self.__new__(self)            #先造一个空对象 __instance
            self.__init__(self.__instance,settings.IP,settings.PORT)   #为空的对象初始化独有的属性
            print(self.__instance.__dict__)  #这一步刚刚造完类,还没运行代码就已经造好了一个空对象,保存到类属性中 
    
        def __call__(self, *args, **kwargs):     #在调用类时才运行
            if len(args)==0 and len(kwargs)==0:
          #思考应该 return 一个已经创建好的Mysql的对象
          #因为call方法只有在调用时才触发,但是要在调用前就应该创建好一个Mysql的对象 return self.__instance ##如果没有会直接传入 obj=self.__new__(self) self.__init__(obj,*args,**kwargs) return obj class Mysql(object,metaclass=Mymeta): def __init__(self,ip,port): self.ip=ip self.port=port #拿到的是同一个内存空间地址 obj=Mysql() obj1=Mysql() obj2=Mysql() print(obj) print(obj1) print(obj2) #拿到是单独的内存地址 obj2=Mysql('3.3.3.3',8888) print(obj2.__dict__)


    注意:
    1.Mysql的调用时才运行__call__ (控制的是类Mysql的调用过程,就是类mysql的实例化过程)
    2.__init__(控制类Mysql这个对象的产生过程,就是类Mymeta的实例化过程) 
    复制代码
    月儿弯弯照九州,几家欢乐几家愁。 对于中年以后的人,十年八年不过是指缝间的事,而对于年轻人,三年五年就可以是一生一世。
  • 相关阅读:
    Visual Studio一直弹出“未将对象引用设置到对象的实例”对话框的处理
    C#如何将十六进制数字符串转byte[]?
    steam游戏存档迁移
    Java实现行列式计算
    Python中单引号、双引号、三引号的区别
    git基本使用方法
    windows(hexo)使用git时出现:warning: LF will be replaced by CRLF
    steam相关插件
    linux的后台运行相关命令
    Ubuntu下启动/重启/停止apache服务器
  • 原文地址:https://www.cnblogs.com/ms520/p/10100063.html
Copyright © 2011-2022 走看看