1. 储备知识
# 储备知识 #4 、自定义元类: class Mymeta(type): # 来控制类Foo的创建 def __init__(self,class_name,class_bases,class_dic): #self=Foo if not class_name.istitle(): raise TypeError('类名的首字母必须大写傻叉') if not class_dic.get('__doc__'): raise TypeError('类中必须写好文档注释,大傻叉') super(Mymeta,self).__init__(class_name,class_bases,class_dic) # # 控制类Foo的调用过程,即控制实例化Foo的过程 def __call__(self, *args, **kwargs): #self=Foo,args=(1111,) kwargs={} #1 造一个空对象obj obj=object.__new__(self) #2、调用Foo.__init__,将obj连同调用Foo括号内的参数一同传给__init__ self.__init__(obj,*args,**kwargs) return obj
·····························
# 单例:所有实例化出来的对象都是同一个
# 所有的配置信息放在一个类中,拿配置文件就实例化类的对象就行
# (问题是每次拿到的对象虽然一样,但内存地址不同,就用到了单例)
# 第一种 基于__new__的单例 # 通过使用__new__来控制实例的创建过程 # 实例化对象的的过程:1.先产生一个空对象(__new__),然后在调用init方法 class Singleton(object): __instance = None def __new__(cls,*args,**kwargs): if not cls.__instance: # 实际object.__new__(self)返回的就是一个对象 cls.__instance = super(Singleton,cls).__new__(cls,*args,**kwargs) return cls.__instance a1 = Singleton() a2 = Singleton()
# 第二种:基于模块的单例模式(用来导入的时候) # 原因:第一次调用模块时,执行一遍,第二次以后调用都不执行(模块调用只执行一次) class Settings(object): x = 100 def foo(self): print("foo") settings = Settings() # 另一个py文件中调用这个模块 # from funcs import settings (这样内存中就有了settings对象,以后用的都是一个了,实现了单例) # 第三种 # 思路: 定义一个类(__instance = None),在类中定义一个类方法 singleton(cls),如果__instance为空,则创建对象 import settings class MySQL(object): __instance = None def __init__(self,ip,port): self.ip = ip self.port = port # 可以保证只有一个对象,但还是可以通过调用类产生新对象(解决:用元类来控制实例化的过程__call__) @classmethod def singleton(cls): if not cls.__instance: # 创建对象 obj = cls(settings.IP,settings.PORT) cls.__instance = obj return cls.__instance obj4=MySQL.singleton() obj5=MySQL.singleton() # id 相同 # 以上参数为配置文件中同一套参数,实现了单例
# 第四种方式,利用元类来实现单例 # 调用类产生对象,实际是调用原类中的__call__方法,自定义__call__方法 # 定义元类 class MyMeta(type): __instance = None # 控制类Foo的调用过程,即控制实例化Foo的过程 def __call__(self, *args, **kwargs): if not MyMeta.__instance: __instance = object.__new__(self) self.__init__(__instance,*args,**kwargs) MyMeta.__instance = __instance return MyMeta.__instance class Printer(metaclass = MyMeta): print(1111) p1 = Printer() p2 = Printer() # id 地址一样