2017-05-26 51 views
0

我試圖讓我的頭繞着元類,但我仍然不能真正理解它的概念。瞭解Python中的元類

據我所知:

任何類本身類型的「類型」的一個實例 - 因此「呼叫」一類的只是調用它的類中的方法__call__ - 這恰好是類型的__call__。的type.__call__的效果是完全:上類似的代碼:

A類: 通 B = A()

的步驟的順序我知道這裏是:

1. type.__call__接收A類本身作爲其第一個參數。

  1. 它調用A.__new__ - 以僞代碼的形式,我們可以編寫instance = A.__new__(cls)作爲運行的代碼。

3.That返回 「A」 類的一個實例

4.然後在實例(instance.__init__()) 調用__init__ ...並返回該實例返回實例

但現在考慮下面的代碼:

class MetaOne(type): 
    def __new__(meta, classname, supers, classdict): 
     print('In MetaOne.new:', meta, classname, supers, classdict, sep='\n...') 
     return type.__new__(meta, classname, supers, classdict) 

class Eggs: 
    pass 

print('making class') 

class Spam(Eggs, metaclass=MetaOne): 
    data = 1 
    def meth(self, arg): 
     return self.data + arg 

print('making instance') 
X = Spam() 
print('data:', X.data, X.meth(2)) 

從這個腳本的輸出如下:

making class 
In MetaOne.new: 
...<class '__main__.MetaOne'> 
...Spam 
...(<class '__main__.Eggs'>,) 
...{'__qualname__': 'Spam', '__module__': '__main__', 'meth': <function Spam.met 
h at 0x00000000010C1D08>, 'data': 1} 
making instance 
data: 1 3 

所以,按照我的理解,這是步驟的順序:

  1. 由於垃圾郵件是MetaOne的一個實例,調用X = Spam()會嘗試調用MetaOne類是不存在的__call__方法。

  2. 由於MetaOne繼承了類型,因此會調用__call__類型爲Spam的方法作爲第一個參數。

此後在MetaOne類的__new__方法調用的土地了,但它應該包含Spam作爲第一個參數。

從哪裏MetaOne類的meta爭論進入畫面。

請幫我理解。

回答

0

由於垃圾郵件是)MetaOne的一個實例,主叫X =垃圾郵件(將試圖 呼叫MetaOne類的__call__方法,該方法是不存在。

這就是你的困惑的soruce - 元類的__call__(或__new____init__)是當你創建類的實例一般叫。

另外,由於是爲MetaOne沒有__call__方法,通常的繼承規則:用在MetaOne的超類的__call__方法(它是type.__call__

元類被調用__new____init__方法時,類本體本身被執行(如你在你的例子中看到的,元類「__new__」中的「打印」出現在「製作實例」文本之前)。

當創建的Span自身的實例,元類方法__new____init__不叫 - 元類__call__被稱爲 - 這是執行類的(跨度的)__new____init__。換句話說:元類__call__負責調用「普通」類__new____init__

由於MetaOne從類型繼承它將調用 型類的呼叫方法與垃圾郵件作爲第一個參數。

它,但你再沒打印語句「視圖」這樣的情況:如果我粘貼在ineractive控制檯,在這一點上打印

class MyMeta(type): 
    def __new__(metacls, name, bases, namespace): 
     print("At meta __new__") 
     return super().__new__(metacls, name, bases, namespace) 
    def __call__(cls, *args, **kwd): 
     print ("at meta __call__") 
     return super().__call__(*args, **kwd) 

def Egg(metaclass=MyMeta): 
    def __new__(cls): 
     print("at class __new__") 

At meta __new__ 

然後,正在進行的交互式會話:

In [4]: fried = Egg() 
at meta __call__ 
at class __new__ 

並且額外的思想扭曲的事情是:「type是類型自己的元類」:這意味着type__call__也負責在元類本身上運行__new____init__方法,當一個新的(非元)類體被執行。