Python之单例模式实现方法

单例模式基本概念

'''
1、什么是单例模式
    单例模式:基于某种方法实例化多次得到实例是同一个
2、为何用单例模式
    当实例化多次得到的对象中存放的属性都一样的情况,应该将多个对象指向同一个内存地址,即同一个实例
3、如何用
'''

一、使用类的方法

# 单例模式实现一:
""" 定义一个类,由类来调用,完成单例的调用过程"""
#配置文件settings内容:
"""
IP='0.0.0.1'
PORT=3306
"""
import settings
class Mysql:
    __instance=None          #通过数据属性来记录用户调用类的方法实例化的状态,调用前状态为Nnoe
    def __init__(self,ip,port):
        self.ip=ip
        self.port=port
    #在类当中定义了一个类方法
    @classmethod
    def from_conf(cls):              #-----------------------将该方法装饰成由类来调用的方法,类来调用将类自动传入
        if cls.__instance is None:   #-----------------------判断该类是否是首次调用该方法,是则返回True
            cls.__instance=cls(settings.IP,settings.PORT)          #类从配置文件中读参数,实例化出的实例(实例即调用类产生的对象)
        #成立与否都返回,所以再外部返回,不用使用else,重复返回
        return cls.__instance        #-----------------------当该方法是第一次和不是第一次被类调用,则返回的结果均是cls.__instance
#单例模式多次都用返回得到的是同一个内存地址
obj1=Mysql.from_conf()               #-----------------------类来调用被装饰器装饰的该方法,将类当做第一个参数自动传入
obj2=Mysql.from_conf()               #-----------------------实例化没有传参,直接从配置文件读,每次调用该方法,实例化的结果都一样,所以叫做单例
obj3=Mysql.from_conf()               #单列模式的好处就是不用每次都进行传参
print(obj1)
print(obj2)
print(obj3)
print(obj1.__dict__)                  #{'ip': '0.0.0.1', 'port': 3306}-----从配置文件中类直接调用绑定给类的方法得到的结果

obj4=Mysql('10.10.10.11',3307)        #直接调用类来是实例化,进行传参,对产生的对象进行初始化,可以和调用类的方法从配置文件中读得到形同的结果
print(obj4)
print(obj4.__dict__)                   #{'ip': '10.10.10.11', 'port': 3307},类直接传参,实例化得到的结果

二、使用装饰器

# 单例模式实现二:
"""自定义一个装饰器,由装饰器来完成单例的过程"""
# 实例化的时候不传参,代表触发单例模式
import settings
'''--------------------------------------------------定义一个装饰器--------------------------------------------'''
def singleton(cls):                                      #定义一个单例模式的函数,把类当做形参
    _instance=cls(settings.IP,settings.PORT)             #也可以方法类中cls. _instance=cls(settings.IP,settings.PORT)
    def wrapper(*args,**kwargs):
        if len(args)==0 and len(kwargs)==0: #Mysql不传参时,直接返回调用类拿到settings中的对象,如果调用类传参了,那么我们就返回类直接调用的产生对象的结果
            return _instance                             #cls._instance
        return cls(*args,**kwargs)                       #直接调用类(进行传参,对产生的随行进行初始化)的返回结果
    return wrapper
'''--------------------------------------------------定义一个装饰器--------------------------------------------'''

@singleton           #Mysql=singleton(Mysql) Mysql=wrapper-----没学类之前我们只学类用装饰器装饰函数,现在用自定义装饰器装饰类
class Mysql:
    def __init__(self,ip,port):
        self.ip=ip
        self.port=port


obj1=Mysql()                    #单例模式每次调用类不用为其进行传参,就如同为ATM的一些功能加上登录装饰器一样,每次登录执行这些功能,必须先登录
obj2=Mysql()                    #不传参,每次调用时,就会执行自定义装饰器中的代码,就会从配置文件中读取内容:_instance=cls(settings.IP,settings.PORT)
obj3=Mysql()
print(obj1)                    #<__main__.Mysql object at 0x000002375BAC2E80>
print(obj2)                    #<__main__.Mysql object at 0x000002375BAC2E80>
print(obj3)                    #<__main__.Mysql object at 0x000002375BAC2E80>

obj4=Mysql('0.0.0.3',3308)     #直接传参,经过装饰器时,会直接走:cls(*args,**kwargs) ,直接调用Mysql,对产生的对象obj4:进行初始化__init__(self,ip,port)
print(obj4)                    #<__main__.Mysql object at 0x0000023762ADBF98>

三、使用元类

# 单例模式实现三
"""自定义一个元类,通过元类内的__call__来完成单例的过程"""
# 基于元类不传参,从配置文件中读取相同的配置文件,传参则以自己传参的为准
import settings
class Mymeta(type):
    def __init__(self,class_name,class_basess,class_dic):                 #self=Mysql
        super(Mymeta,self).__init__(class_name,class_basess,class_dic)    #继承元类中的属性
        self.__instance=self.__new__(self)                                #造出Mysql的空对象
        self.__init__(self.__instance,settings.IP,settings.PORT)          #对Mysql的空对象从配置文件中传参进行初始化

    def __call__(self, *args, **kwargs):          #会在调用类这个对象是自动触发
        if len(args)==0 and len(kwargs)==0:       #判断如果不传参时,直接返回我们从配置文件中初始会的对象
            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


obj1=Mysql()            #不传参直接调用类,产生对象,此时的对象,已经从配置文件中读取了配置信息,而非是一个空对象
obj2=Mysql()            #每次调用该类读的是同一个配置文件,得到的对象的内存地址也是一样的
obj3=Mysql()
# 以上三者调用均是没有进行传参,调用类这个对象会触发__call__,会判断如果没有进行传参,则直接调用配置文件拿到返回的结果
print(obj1)             #<__main__.Mysql object at 0x000002659486F2E8>
print(obj2)
print(obj3)

obj4=Mysql('0.0.0.3',3308) #直接为类进行传参,进过判断就不会走配置文件了,而是直接造了一个空对象,然后对其进行初始化
print(obj4)             #<__main__.Mysql object at 0x000002659B88BF98>

猜你喜欢

转载自www.cnblogs.com/sui776265233/p/9254208.html
今日推荐