2015-02-11 33 views
3

在一個名爲exp.py(下面)的文件中,我試圖理解Python中的元類。Python元類行爲(不調用__new__),是否有解釋?

class A(type): 
    def __new__(cls, name, bases, dct): 
     print "cls is: ", cls 
     print "name is: ", name 
     print "bases is: ", bases 
     print "dct is: ", dct 
     print 
     return super(A, cls).__new__(cls, name, bases, dct) 

class B(object): 
    __metaclass__ = A 

class C(B): pass 

class D(type): 
    def __new__(cls, name, bases, dct): 
     print "cls is: ", cls 
     print "name is: ", name 
     print "bases is: ", bases 
     print "dct is: ", dct 
     return type(name, bases, dct) 

class E(object): 
    __metaclass__ = D 

class F(E): pass 

在終端:看來當元類的__new__方法使用的「類型」的構造函數構造一類像,其__new__方法沒有得到一個類的子類使用它作爲元類稱爲

>>> from exp import * 
cls is: <class 'exp.A'> 
name is: B 
bases is: (<type 'object'>,) 
dct is: {'count': 0, '__module__': 'exp', '__metaclass__': <class 'exp.A'>, '__init__': <function __init__ at 0x107eb9578>} 

cls is: <class 'exp.A'> 
name is: C 
bases is: (<class 'exp.B'>,) 
dct is: {'__module__': 'exp'} 

cls is: <class 'exp.D'> 
name is: E 
bases is: (<type 'object'>,) 
dct is: {'count': 0, '__module__': 'exp', '__metaclass__': <class 'exp.D'>, '__init__': <function __init__ at 0x107ebdb18>} 
>>> 

正如你所看到的,當類F的定義被加載時,元類D的__new__方法不會被調用。 (如果它已被調用,那麼關於F級的信息也將被打印。)

有人可以幫我解釋一下嗎?


相關崗位:我讀What is a metaclass in Python?,而且似乎遇到了一句類似的話,「這裏需要的__metaclass__屬性不會被繼承小心,父(Bar.__class__)的元類將是如果。 Bar使用了__metaclass__屬性,該屬性創建了帶有type()的Bar(而不是type.__new__()),該子類不會繼承該行爲。「但我並沒有完全理解這一點。

回答

3

在第二種情況下,而不是返回你實際返回的type實例的元類的實例,這反過來將新創建的E類的__class__屬性爲<type 'type'>,而不是D。因此as per the rule 2 Python會檢查基類的__class__屬性(或type(E)E.__class__)並決定使用type作爲F的元類,因此在這種情況下D__new__永遠不會被調用。

  • 如果存在dict['__metaclass__'],則使用它。
  • 否則,如果至少有一個基類,則使用其元類(這首先查找__class__屬性,如果未找到,則使用其類型)。

所以,正確的方法是調用類型的__new__方法在元類的__new__方法:

class D(type): 
    def __new__(cls, name, bases, dct): 
     print "cls is: ", cls 
     print "name is: ", name 
     print "bases is: ", bases 
     print "dct is: ", dct 
     return type.__new__(cls, name, bases, dct) 

class E(object): 
    __metaclass__ = D 

class F(E): pass 

class A(object): 
    pass 

輸出:

cls is: <class '__main__.D'> 
name is: E 
bases is: (<type 'object'>,) 
dct is: {'__module__': '__main__', '__metaclass__': <class '__main__.D'>} 
cls is: <class '__main__.D'> 
name is: F 
bases is: (<class '__main__.E'>,) 
dct is: {'__module__': '__main__'} 
+0

大回答謝謝!順便說一下,我對這句話有一些疑問,「(這首先查找'__class__'屬性,如果找不到,則使用它的類型)」。 1.在什麼情況下會找不到'__class__'屬性? 2.在什麼類型的情況下,類的'__class__'屬性與它的類型不同(用'type()'確定)?謝謝 – platypus 2015-02-11 23:26:12

+0

@platypus舊式類沒有這個屬性,甚至'type()'的輸出也不一樣。對於新式類,默認類型是'type',對於舊式類,它是'classobj'。 [新風格和經典類](https://docs.python.org/2/reference/datamodel.html#new-style-and-classic-classes) – 2015-02-11 23:55:31

相關問題