1. 程式人生 > >python8之類的起源與metaclass

python8之類的起源與metaclass

自己 傳統 ges ima 方法 靜態變量 我想 -a print

一、概述

  前面我們學習了大篇幅的關於類,通過類創建對象,那我們想知道這個類到底是怎麽產生的呢?它的一切來源是什麽?還有對象,對象是通過什麽方法創建的,現在我們一頭霧水,行的,下面我們就來揭開類的面紗,看看類和對象到底是怎麽創建的,通過什麽創建的。

二、類的起源

2.1 傳統創建類

class Foo(object):
    def __init__(self,name):
        self.name = name
 
f = Foo("shuaigaogao")

f 是通過 Foo 類實例化的對象,其實,不僅 f 是一個對象,Foo類本身也是一個對象,因為在Python中一切事物都是對象,

按照一切事物都是對象的理論:obj對象是通過執行Foo類的構造方法創建,那麽Foo類對象應該也是通過執行某個類的 構造方法 創建。

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