7.13 元類 元類:類的類就是元類,我們用class定義的類來產生我們自己的對象的,內置元類type是用來專門產生class定義的類 7.131 用內置的元類type,來實例化得到我們的類 7.132 __call__方法 在調用對象時自動觸發__call__的執行 7.133 自定義元類來控制類 ...
7.13 元類
元類:類的類就是元類,我們用class定義的類來產生我們自己的對象的,內置元類type是用來專門產生class定義的類
code=""" global x x=0 y=2 """ #字元串內聲明的名稱是全局,其他為局部名稱 global_dic={'x':100000} local_dic={} # 運行字元串內代碼 exec(code,global_dic,local_dic) # 把全局名稱空間的名稱放入global_dic,把局部的放入local_dic print(global_dic) #{'x': 0} print(local_dic) #{'y': 2}
7.131 用內置的元類type,來實例化得到我們的類
class_name='Chinese' class_bases=(object,) #基類 class_body=""" country="China" def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex def speak(self): print('%s speak Chinese' %self.name) """ class_dic={} exec(class_body,{},class_dic) # 類的三大要素 print(class_name,class_bases,class_dic) # Chinese (<class 'object'>,) {'country':'China', '__init__': <function __init__ at ...>, 'speak': <function speak at....>} Chinese=type(class_name,class_bases,class_dic) #實例化一個類 print(Chinese) #<class '__main__.Chinese'> p=Chinese('egon',18,'male') #實例化對象p print(p.name,p.age,p.sex) # egon 18 male #說明和class定義的類功能相同
7.132 __call__
方法
在調用對象時自動觸發__call__
的執行
class Foo: def __init__(self): pass def __call__(self, *args, **kwargs):# 調用對象,則會自動觸發對象下的綁定方法__call__的執行, print('__call__',*args, **kwargs)# 然後將對象本身當作第一個參數傳給self,將調用對象時括弧內的值傳給*args與**kwargs obj=Foo() obj(1,2,3,a=1,b=2,c=3) #對象調用
7.133 自定義元類來控制類的創建行為
class Mymeta(type): def __init__(self,class_name,class_bases,class_dic): #self=Foo print(class_name) print(class_bases) print(class_dic) 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=Mymeta('Foo',(object,),class_dic) class Foo(object,metaclass=Mymeta): # metaclass=Mymeta創建自定義元類 """ 文檔註釋 """
7.134 自定義元類來控制類的調用
控制類Foo的調用過程,即控制實例化Foo的過程
class Mymeta(type): def __init__(self,class_name,class_bases,class_dic): #self=Foo print(class_name) print(class_bases) print(class_dic) 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 #Foo=Mymeta('Foo',(object,),class_dic) class Foo(object,metaclass=Mymeta): x=1 def __init__(self,y): self.y=y def f1(self): print('from f1') obj=Foo(1111) #Foo.__call__() print(obj) #<__main__.Foo object at 0x000002019EE1BB70> print(obj.y) # 1111 print(obj.f1) #<bound method Foo.f1 of <__main__.Foo object at 0x000002019EE1BB70>> print(obj.x) # 1
7.14 單例模式
對於對象通過相同的配置文件進行實例化,可以使幾個對象使用同一個記憶體地址,節省記憶體
import settings class MySQL: __instance=None def __init__(self,ip,port): self.ip=ip self.port=port @classmethod def singleton(cls): if not cls.__instance: obj=cls(settings.IP, settings.PORT) cls.__instance=obj return cls.__instance obj1=MySQL('1.1.1.2',3306) obj2=MySQL('1.1.1.3',3307) obj3=MySQL('1.1.1.4',3308) obj4=MySQL.singleton() # obj4=MySQL(settings.IP,settings.PORT) obj5=MySQL.singleton() obj6=MySQL.singleton() print(obj4.ip,obj4.port) # 1.1.1.1 3306 print(obj4 is obj5 is obj6) # True