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的實例化過程) 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM