2012-06-21 163 views
2

我想在類的創建過程中自動運行在任何派生類的基類中定義的類方法。例如:Python派生類在派生類上自動運行類方法

class Base(object): 
    @classmethod 
    def runme(): 
    print "I am being run" 

    def __metclass__(cls,parents,attributes): 
    clsObj = type(cls,parents,attributes) 
    clsObj.runme() 
    return clsObj 


class Derived(Base): 
    pass: 

這裏發生的是,當創建Base時,'runme()'將會觸發。但是,創建派生時沒有任何反應。

問題是:如何在創建派生的時使'runme()'也被觸發。

這是我至今想:如果我明確設置派生元類基地的,它會工作。但我不希望發生這種情況。我基本上想要派生的使用基地的元類沒有我必須明確地設置它。

+0

你爲什麼定義爲'喜歡這個類裏面__metaclass__'?它應該被用來將元類設置爲一個外部定義的類。 – BrenBarn

+0

@BrenBarn:但爲什麼它不能像我用過的那樣使用它。據我所見,__metaclass__屬性是指向一個類對象還是一個函數對象應該不重要。但它確實很重要,我認爲你是對的。我想知道爲什麼?如果可以,請提供一些簡單的代碼示例。 –

回答

2

參見this answer。基本上,在調用type(cls,parents,attributes)時,您正在創建一個類而不傳遞關於該類的元類的信息。因此,返回的類沒有您想要的元類;相反,它具有元類type。 (具有諷刺意味的是,通過定義__metaclass__這樣做,你明確地導致你的類不是而是擁有那個元類。)不需要直接調用類型,你需要調用type.__new__(meta, cls, parents, attrs),其中meta是元類。

但是,在內聯定義__metaclass__時無法實現此目的。從您的__metaclass__方法中,您無法引用該方法,因爲它是尚未定義的類的方法。你想做點像

def __metaclass__(cls, bases, attrs): 
    type.__new__(metaclassGoesHere, cls, bases, attrs) 

。 。 。但是沒有什麼東西可以放在metaclassGoesHere中,使它做正確的事情,因爲你試圖引用的是你試圖引用它的方法。

所以只需從外部定義你的元類。

+0

謝謝@BrenBarn。你已經非常清楚這件事了。基本上,需要使用__new__來控制元類對象的實際創建,我們可以控制它並設置該對象的元類。謝謝。 –

0

重命名您的__init__()方法runme()__init__(self)切勿覆蓋,它會被調用每次你做Derived

class Base(object): 
    def __init__(self): 
     print "I am being run" 

class Derived(Base): 
    pass 

dummy_instance = Derived() 

複製的實例,並粘貼到時候,它將打印I am being run

+0

是的,我知道這將發生派生實例。但我不是在談論派生實例,我在談論派生類。 __init__函數初始化實例屬性,但我希望初始化發生在類級別上。這是爲我設計的API,所以我真的需要一些元類魔術,但我不明白爲什麼它不被繼承... –

+0

你能提供這個pls的用例@BarrySteyn –

+0

@JonClements I我正在使用SQLalchemy來創建一個ORM。一種做事的模式是使用所謂的聲明性反射模式,但是這需要調用基類的類方法。一旦加載類,我希望自動調用此方法。 –

0

試試這個,

class MyMetaclass(type): 

    def __new__(cls, name, bases, dct): 

     runme() 

     return super(MyMetaclass, cls).__new__(cls, name, bases, uppercase_attr) 
0

如果你想要做的事創建類時,你必須做在__metaclass____init__方法。

class foo(object): 
    @classmethod 
    def method(cls): 
     print 'I am being run by', cls.__name__ 

    class __metaclass__(type): 
     def __init__(self, *args, **kwargs): 
      type.__init__(self, *args, **kwargs) 
      self.method() 

class bar(foo): pass 

它打印:

I am being run by foo 
I am being run by bar