【目錄】
一、什么是元類
二、類是如何產生的——關鍵字class創造類的程序
三、如何自定義元類來控制類的產生
四、內置方法 __call__
五、自定義元類控制類的呼叫=》類的物件的產生
六、再訪——屬性查找
七、單例模式
一、什么是元類
一切都源自于一句話:一切皆為物件
# 元類就是用來實體化產生類的類
# 關系:元類---實體化---->類(People)---實體化---->物件(obj)
class People: def __init__(self,name,age): self.name=name self.age=age def say(self): print('%s:%s' %(self.name,self.name)) print(People.__dict__) # 如何得到物件 # obj=呼叫類() obj=People('egon',18) print(type(obj)) # 如果說類也是物件 # People=呼叫類(,,,) # 查看內置的元類: # 1、type是內置的元類 # 2、我們用class關鍵字定義的所有的類以及內置的類都是由元類type實體化產生 print(type(People)) print(type(int))
二、類是如何產生的——關鍵字class創造類的程序
類有三大特征:類名,類的基類,類體
類有三大特征: # 1、類名 class_name="People" # 2、類的基類 class_bases=(object,) # 3、執行類體代碼拿到類的名稱空間 class_dic={} class_body=""" def __init__(self,name,age): self.name=name self.age=age def say(self): print('%s:%s' %(self.name,self.name)) """ exec(class_body,{},class_dic) # print(class_dic) # 4、呼叫元類 People=type(class_name,class_bases,class_dic)
三、如何自定義元類來控制類的產生
class Mymeta(type): # 只有繼承了type類的類才是元類 # 空物件,"People",(),{...} def __init__(self,x,y,z): print('run22222222222....') print(self) # print(x) # print(y) # print(z) # print(y) # if not x.istitle(): # raise NameError('類名的首字母必須大寫啊!!!') # 當前所在的類,呼叫類時所傳入的引數 def __new__(cls, *args, **kwargs): # 造Mymeta的物件 print('run1111111111.....') # print(cls,args,kwargs) # return super().__new__(cls,*args, **kwargs) return type.__new__(cls,*args, **kwargs) People=Mymeta("People",(object,),{...}) # 呼叫Mymeta發生三件事,呼叫Mymeta就是type.__call__ # 1、先造一個空物件=>People,呼叫Mymeta類內的__new__方法 # 2、呼叫Mymeta這個類內的__init__方法,完成初始化物件的操作 # 3、回傳初始化好的物件 class People(metaclass=Mymeta): def __init__(self,name,age): self.name=name self.age=age def say(self): print('%s:%s' %(self.name,self.name))
強調:
只要是呼叫類,那么會一次呼叫
1、類內的__new__
2、類內的__init__
四、內置方法 __call__
class Foo: def __init__(self,x,y): self.x=x self.y=y # obj,1,2,3,a=4,b=5,c=6 def __call__(self,*args,**kwargs): print('===>',args,kwargs) return 123 obj=Foo(111,222) # print(obj) # obj.__str__ res=obj(1,2,3,a=4,b=5,c=6) # res=obj.__call__() print(res)
應用:如果想讓一個物件可以加括號呼叫,需要在該物件的類中添加一個方法__call__
總結:
物件()->類內的__call__
類()->自定義元類內的__call__
自定義元類()->內置元類__call__
五、自定義元類控制類的呼叫=》類的物件的產生
class Mymeta(type): # 只有繼承了type類的類才是元類 def __call__(self, *args, **kwargs): # 1、Mymeta.__call__函式內會先呼叫People內的__new__ people_obj=self.__new__(self) # 2、Mymeta.__call__函式內會呼叫People內的__init__ self.__init__(people_obj,*args, **kwargs) # print('people物件的屬性:',people_obj.__dict__) people_obj.__dict__['xxxxx']=11111 # 3、Mymeta.__call__函式內會回傳一個初始化好的物件 return people_obj # 類的產生 # People=Mymeta()=》type.__call__=>干了3件事 # 1、type.__call__函式內會先呼叫Mymeta內的__new__ # 2、type.__call__函式內會呼叫Mymeta內的__init__ # 3、type.__call__函式內會回傳一個初始化好的物件 class People(metaclass=Mymeta): def __init__(self,name,age): self.name=name self.age=age def say(self): print('%s:%s' %(self.name,self.name)) def __new__(cls, *args, **kwargs): # 產生真正的物件 return object.__new__(cls) # 類的呼叫 # obj=People('egon',18) =》Mymeta.__call__=》干了3件事 # 1、Mymeta.__call__函式內會先呼叫People內的__new__ # 2、Mymeta.__call__函式內會呼叫People內的__init__ # 3、Mymeta.__call__函式內會回傳一個初始化好的物件 obj1=People('egon',18) obj2=People('egon',18) # print(obj) print(obj1.__dict__) print(obj2.__dict__)
六、再訪——屬性查找
# 屬性查找的原則:物件-》類-》父類
# 切記:父類 不是 元類
class Mymeta(type): n=444 def __call__(self, *args, **kwargs): #self=<class '__main__.StanfordTeacher'> obj=self.__new__(self) # StanfordTeacher.__new__ # obj=object.__new__(self) print(self.__new__ is object.__new__) #True self.__init__(obj,*args,**kwargs) return obj class Bar(object): # n=333 # def __new__(cls, *args, **kwargs): # print('Bar.__new__') pass class Foo(Bar): # n=222 # def __new__(cls, *args, **kwargs): # print('Foo.__new__') pass class StanfordTeacher(Foo,metaclass=Mymeta): # n=111 def __init__(self,name,age): self.name=name self.age=age obj=StanfordTeacher('lili',18) print(obj.__dict__) # print(obj.n) # print(StanfordTeacher.n)
七、單例模式
https://www.cnblogs.com/the3times/p/12755968.html
參考資料:
https://zhuanlan.zhihu.com/p/109336845
https://www.cnblogs.com/linhaifeng/articles/6204014.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/158685.html
標籤:Python
