2011-05-15 93 views
9

爲了特定的調試目的,我想包裝一個任意對象的函數來執行額外的任務,如將對象的最後一個值寫入文件。猴子補丁__del__到新函數

理想我想寫 猴(x)的 ,它應該意味着,當X被刪除

x的最終值印刷現在我想通德爾是一個類的方法。所以下面是一個開始:

class Test: 
    def __str__(self): 
     return "Test" 

def p(self): 
    print(str(self)) 

def monkey(x): 
    x.__class__.__del__=p 

a=Test() 
monkey(a) 
del a 

但是,如果我想只猴子特定的對象,我想我需要動態地重寫他們的類到一個新的?此外,無論如何,我需要這樣做,因爲我無法訪問內置類型的del

任何人都知道如何實現它?

回答

6

雖然特殊的「雙下劃線」的方法,如__del____str____repr__等均可猴子打補丁的情況下的水平,他們就會被忽略,除非它們被直接(例如,如果你採取Omnifarious的答案:del a將不會打印的東西,但a.__del__()會)。

如果你仍然想猴子修補單個實例a在運行時A類的,該解決方案是動態創建一個類A1這是從A導出,然後更改a的類新創建A1。是的,這是可能的,a將表現得好像什麼都沒有改變 - 除了現在它包括你的猴子修補方法。

下面是基於通用功能我寫了另外一個問題的解決方案: Python method resolution mystery

def override(p, methods): 
    oldType = type(p) 
    newType = type(oldType.__name__ + "_Override", (oldType,), methods) 
    p.__class__ = newType 


class Test(object): 
    def __str__(self): 
     return "Test" 

def p(self): 
    print(str(self)) 

def monkey(x): 
    override(x, {"__del__": p}) 

a=Test() 
b=Test() 
monkey(a) 
print "Deleting a:" 
del a 
print "Deleting b:" 
del b 
+2

這種方法的兩個問題:首先,不會像int或list這樣的堆類型工作,因爲你不能重新賦值它們的'__class__'。其次,類型檢查將導致不同的結果,這取決於對象是否是猴子。這可能會導致非常混亂的錯誤。 – pillmuncher 2011-05-15 20:25:56

+0

你可以分配給__class__?哇,那只是...哇。 – drxzcl 2011-05-15 20:27:19

+1

在我上面的評論中有一個錯字:它應該是'非堆類型'。 – pillmuncher 2011-05-15 20:45:57

0

您也可以繼承某些基類並覆蓋__del__方法(然後只需要在構建對象時重寫類)。 或者您可以使用super內置方法。

+0

這個訣竅是針對一些adhoc調試,所以我寧願不定義真正的基類。另外,我需要記住用__del__函數從任何派生類中調用超類。最後,這對內置插件不起作用。我希望有一種方法也可以猴子正常列表?! – Gerenuk 2011-05-15 18:48:47

+0

http://stackoverflow.com/questions/192649/can-you-monkey-patch-methods-on-core-types-in-python - 第二個答案在這裏是一個很好的解釋 – 2011-05-15 18:59:20

0

你可以猴子修補一個單獨的對象。 self不會通過這種方式傳遞給您以猴子補丁的方式傳遞的函數,但這很容易通過functools.partial補救。

例子:

def monkey_class(x): 
    x.__class__.__del__ = p 

def monkey_object(x): 
    x.__del__ = functools.partial(p, x) 
+0

你試過嗎?不知道我是否犯了一些錯誤,但顯然x .__ del__是無效的。可能是因爲del是嚴格的類方法?!不知何故,我無法得到它的工作:(我感覺.partial保持對x的引用,以便它不是垃圾收集?! – Gerenuk 2011-05-15 19:13:26

+0

它不起作用,因爲特殊的方法只能用類dict調用。解決方案只適用於「常規」方法 – 2011-05-15 20:02:08

+0

@Boaz Yaniv:糟糕,你每天都會學到新東西,我將這個答案留在這裏作爲對其他人的警告:-) – Omnifarious 2011-05-15 21:16:36

0

del a刪除名稱通過名稱引用「一」從命名空間,而不是對象。看到這一點:

>>> x = 7 
>>> y = x 
>>> del x 
>>> print y 
7 

此外,some_object.__del__is not guaranteed to be called at all

此外,我已經回答了您的問題here(德文)。