1. 程式人生 > >12.python-metaclass元類

12.python-metaclass元類

*args bject tro 接收 自定義 all metaclass 控制 module

1.python中一切皆是對象,類本身也是一個對象,當使用關鍵字class的時候,python解釋器在加載class的時候會創建一個對象(這裏的對象指的是類而非類的實例)

class Foo:
      pass

#f1是通過Foo類實例化的對象
f1=Foo()
#通過type查看f1這個對象由哪一個類產生
print(type(f1))           #輸出:<class ‘__main__.Foo‘>    f1這個對象由Foo類創建
#通過type查看Foo這個類由哪一個對象產生
print(type(Foo))          #輸出:<class ‘type‘>            Foo這個類的類是type,type是python的一個內建元類

返回:
<class ‘__main__.Foo‘>
<class ‘type‘>
2.什麽是元類
(1)元類是類的類,是類的模版
(2)元類是用來控制如何創建類的,正如類是創建對象的模版一樣
(3)元類的實例為類,正如類的實例為對象(f1對象是Foo類的一個實例,Foo類是type類的一個實例)
(4)typy是python的一個內建元類(不指定類的類是誰默認用typy去生成),用來直接控制生成類,python中任何class定義的類其實都是type類實例化的對象
3.創建元類的兩種方式
方式一:

class Foo:
    def __init__(self):    #加上構造函數__init__
pass #查看Foo這個類 print(Foo) #查看Foo這個類裏的屬性 print(Foo.__dict__)

返回:
class ‘__main__.Foo‘>
{‘__module__‘: ‘__main__‘, ‘__init__‘: <function Foo.__init__ at 0x00399858>, ‘__dict__‘: <attribute ‘__dict__‘ of ‘Foo‘ objects>, ‘__weakref__‘: <attribute ‘__weakref__‘ of ‘Foo‘ objects>, ‘__doc__‘: None}
方式二:

def __init__(self,name,age):   #頂級作用域裏定義構造函數__init__
    self.name=name
    self.age=age

def test(self):               #創造test方法
    print(我是test方法)

#創建元類FFo是由type類產生的
FFo=type(FFo,(object,),{x:1,__init__:__init__,test:test})    #實例化type傳三個參數進去,參數1:類名字符串形式,參數2:繼承的父類元祖的形式(新式類默認object),參數3:類的屬性‘x‘:1和方法屬性__init__‘:__init__和test‘:test放在屬性字典裏
#查看Foo這個類
print(FFo)
#用FFo這個對象產生實例傳倆個參數xixi和18
f1=FFo(xixi,18)
#調f1的x的類屬性
print(f1.x)        #返回:1
#調f1的name的類屬性
print(f1.name)     #返回:xixi
#調f1的方法實例化
f1.test()          #返回:我是test方法
#查看Foo這個類裏的屬性
print(FFo.__dict__)

返回:
<class ‘__main__.FFo‘>
1
xixi
我是test方法
{‘x‘: 1, ‘__init__‘: <function __init__ at 0x01D8C6A8>, ‘test‘: <function test at 0x02109858>, ‘__module__‘: ‘__main__‘, ‘__dict__‘: <attribute ‘__dict__‘ of ‘FFo‘ objects>, ‘__weakref__‘: <attribute ‘__weakref__‘ of ‘FFo‘ objects>, ‘__doc__‘: None}
4.一個類沒有聲明自己的元類,默認他的元類就是type,除了使用元類type,用戶也可以通過繼承type來自定義元類
5.元類如何控制類的創建

#定制元類必MyType須繼承type類
class MyType(type):
    def __init__(self,a,b,c):          #第二步:接收metaclass=MyType傳來的四個參數,得到結果Foo,Foo這個類就此生成
        print(觸發元類的構造函數執行)
        #print(a)                      #參數二傳過來的類名
        #print(b)                      #參數三傳過來繼承的object
        #print(c)                      #參數四傳過來類的屬性字典

    def __call__(self, *args, **kwargs): #第四步:接收self是Foo本身,*args, **kwargs接收Foo傳的參數xixi
        print(觸發元類裏__call__方法)
        #print(self)                    #查看self是Foo:<class ‘__main__.Foo‘>
        #print(args,kwargs)             #查看*args, **kwargs傳過來的值(‘xixi‘,) {}
        obj = object.__new__(self)      #產生一個對象   #第五步:生成Foo的對象。所有類都繼承object,object.__new__就是創建一個新的對象把self傳進去,self就是Foo,得到的就是Foo這個對象,Foo產生的對象就是f1賦值給obj
        self.__init__(obj, *args, **kwargs)  #第六步:給f1做封裝的屬性的事。self.__init__相當於執行Foo.__init__ 就是在執行def __init__(self,name):要傳倆個參數self傳obj就是f1  name傳 *args, **kwargs
        return obj                          #第七步:返回obj。__call__得到返回值才賦值給f1

#定義Foo這個類聲明它的元類是MyType,只要一class Foo會觸發MyType(‘Foo‘,(object,),{})
class Foo(metaclass=MyType):           #第一步:執行class Foo會觸發class MyType(type):傳四個參數給__init__方法
    def __init__(self,name):           #第八步:跳到Foo的__init__方法
        self.name=name                 #第九步:給f1封裝屬性,name的屬性封裝到f1的屬性字典裏。得到f1.name=name

#調用
f1=Foo(xixi)                         #第三步:Foo(‘xixi‘) 在呼叫MyType(type):裏的__call__方法   #第十步:__call__運行完畢代表Foo(‘xixi‘) 運行完畢把變量返值回給f1
#查看f1
print(f1)
#查看f1字典裏的屬性
print(f1.__dict__)

返回:
觸發元類的構造函數執行
觸發元類裏__call__方法
<__main__.Foo object at 0x027C49D0>
{‘name‘: ‘xixi‘}

12.python-metaclass元類