zoukankan      html  css  js  c++  java
  • 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的实例化过程) 
  • 相关阅读:
    强化学习的基本迭代方法
    基于文本描述的事务聚类
    学习强化学习之前需要掌握的3种技能
    其它 华硕 ASAU S4100U 系统安装 win10安装 重装系统 Invalid Partition Table 解决
    数据分析 一些基本的知识
    Python 取样式的内容 合并多个文件的样式 自定义样式
    电商 Python 生成补单公司需要的评论格式3
    SpringBlade 本地图片上传 生成缩略图
    SQL Server 字符串截取
    SpringBlade 本地图片上传
  • 原文地址:https://www.cnblogs.com/yangzhizong/p/9315672.html
Copyright © 2011-2022 走看看