python8之類的起源與metaclass
一、概述
前面我們學習了大篇幅的關於類,通過類創建對象,那我們想知道這個類到底是怎麽產生的呢?它的一切來源是什麽?還有對象,對象是通過什麽方法創建的,現在我們一頭霧水,行的,下面我們就來揭開類的面紗,看看類和對象到底是怎麽創建的,通過什麽創建的。
二、類的起源
2.1 傳統創建類
class Foo(object): def __init__(self,name): self.name = name f = Foo("shuaigaogao")
f 是通過 Foo 類實例化的對象,其實,不僅 f 是一個對象,Foo類本身也是一個對象,因為在Python中一切事物都是對象,
print(type(f)) #輸出:<class ‘__main__.Foo‘> 表示:f 對象由Foo類創建 print(type(Foo)) #輸出:<class ‘type‘> 表示:Foo類對象由 type 類創建
所以,f對象是Foo類的一個實例,Foo類對象是 type 類的一個實例,即:Foo類對象 是通過type類的構造方法創建
2.2 type創建類
說明: type創建類的格式,類名 = type(‘類名‘,(父類,),{‘方法名‘:方法的內存地址})
def func(self): #創建方法 print("hello {0}".format(self.name)) def __init__(self,name): #創建構造方法 self.name = name Foo = type("Foo",(object,),{"talk":func,"__init__":__init__}) #通過type創建類,如果是經典類的話則寫成:Foo = type("Foo",(),{"talk":func,"__init__":__init__}) f = Foo("shuaigaogao") #創建對象 f.talk() #輸出 hello shuaigaogao
總結:類 是由 type 類 實例化產生的
值得註意的是,新式類的寫法,在繼承父類那邊,你繼承一個父類後面就要加一個逗號,加逗號,它就把它當做一個元組,不加逗號,就是一個值了
三、__new__方法
3.1 概念
new方法是類自帶的一個方法,可以重構,__new__方法在實例化的時候也會執行,並且先於__init__方法之前執行.
class Foo(object): def __init__(self,name): self.name = name print("Foo __init__") def __new__(cls, *args, **kwargs): print("Foo __new__",cls, *args, **kwargs) return object.__new__(cls) f = Foo("shuaigaogao") #輸出 Foo __new__ <class ‘__main__.Foo‘> shuaigaogao #執行了new方法 Foo __init__ #執行了__init__方法
3.2 new方法作用
作用:所有對象都是通過new方法來實例化的,new裏面調用了init方法,所以在實例化的過程中先執行的是new方法,而不是init方法。
①重構__new__方法
class Foo(object): def __init__(self,name): self.name = name print("Foo __init__") def __new__(cls, *args, **kwargs): print("Foo __new__",cls, *args, **kwargs) f = Foo("shuaigaogao") #實例化 #輸出 Foo __new__ <class ‘__main__.Foo‘> shuaigaogao
由上面的例子看出,沒有執行__init__方法
②重構__new__方法,並繼承父類的__new__方法
class Foo(object): def __init__(self,name): self.name = name print("Foo __init__") def __new__(cls, *args, **kwargs): #cls相當於傳入類Foo print("Foo __new__",cls, *args, **kwargs) return object.__new__(cls) #繼承父類的__new__方法,這邊必須以返回值的形式繼承 f = Foo("shuaigaogao") #輸出 Foo __new__ <class ‘__main__.Foo‘> shuaigaogao Foo __init__
由上面不難看出,大多數情況下,你都不要去重構你的__new__方法,因為你父類中已經有__new__方法了,已經幫你寫好了怎麽去創建類,如果你重寫的話,就會覆蓋父類的裏面的__new__方法。但是你重構可以增加一點小功能,但是你覆蓋了以後還是需要繼承父類回來,要不然你的這個實力就創建不了。
3.3 使用場景
我想對我自己寫的一些類進行定制,就在它實例化之前就進行定制,就可以用到__new__方法,new方法就是用來創建實力的,重構new方法,必須以返回值的形式繼承父類的new方法。
①需求:我在創建對象時候,同時創建一個類變量
class Foo(object): def __init__(self,name): self.name = name print("Foo __init__") def __new__(cls, *args, **kwargs): #cls相當於是傳入的類名Foo cls.name = "shuaigaogao" #創建對象是定義靜態變量 print(cls.name) return object.__new__(cls) #繼承父類的__new__方法 f = Foo("shuaigaogao") print(Foo.name) #輸出 shuaigaogao Foo __init__ shuaigaogao
四、__metaclass__方法
4.1 metaclass作用
類 是由 type 類實例化產生
那麽問題來了,類默認是由 type 類實例化產生,type類中如何實現的創建類?類又是如何創建對象?
答:類中有一個屬性 __metaclass__,其用來表示該類由 誰 來實例化創建,所以,我們可以為 __metaclass__ 設置一個type類的派生類,從而查看 類 創建的過程。
class MyType(type): def __init__(self,*args,**kwargs): print("Mytype __init__",*args,**kwargs) def __call__(self, *args, **kwargs): print("Mytype __call__", *args, **kwargs) obj = self.__new__(self) print("obj ",obj,*args, **kwargs) print(self) self.__init__(obj,*args, **kwargs) return obj def __new__(cls, *args, **kwargs): print("Mytype __new__",*args,**kwargs) return type.__new__(cls, *args, **kwargs) print(‘here...‘) class Foo(object,metaclass=MyType): def __init__(self,name): self.name = name print("Foo __init__") def __new__(cls, *args, **kwargs): print("Foo __new__",cls, *args, **kwargs) return object.__new__(cls) f = Foo("Alex") print("f",f) print("fname",f.name) 自定義元類
4.2 執行順序
類的生成 調用 順序依次是 __new__ --> __init__ --> __call__
https://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python
python8之類的起源與metaclass