2012-11-15 70 views
5

我知道,在Python有可能在運行時的方法添加到類:覆蓋在運行時__setattr__

class Test: 
    def __init__(self): 
     self.a=5 

test=Test() 

import types 
def foo(self): 
    print self.a 
test.foo = types.MethodType(foo, test) 
test.foo() #prints 5 

而且我也知道,它可能覆蓋默認SETATTR類定義:

class Test: 
    def __init__(self): 
     self.a=5 
    def __setattr__(self,name,value): 
     print "Possibility disabled for the sake of this test" 

test=Test() #prints the message from the custom method called inside __init__ 

然而,現在看來,這是不可能的,在運行時SETATTR覆蓋:

class Test: 
    def __init__(self): 
     self.a=5 

test=Test() 

import types 
def __setattr__(self,name,value): 
    print "Possibility disabled for the sake of this test" 
test.__setattr__ = types.MethodType(__setattr__, test) 
test.a=10 #does the assignment instead of calling the custom method 

在最後兩種情況下,dir(測試)還報告了方法setattr。但是,在第一種情況下,它正常工作,而在第二種情況下則不正確。請注意,我也可以明確地調用它,在這種情況下它可以工作。似乎是這樣,雖然該方法已被定義,但尚未正確映射以覆蓋默認分配方法。我錯過了什麼嗎?

我正在使用Python 2.7。問題主要是學術問題,因爲從程序設計的角度來看,做這樣的事情可能不是一個好主意,但它仍然值得回答 - 儘管我搜索了,但我無法在任何地方找到它。

回答

2

見Python文檔的這一部分:Special method lookups for new-style classes

對於新樣式類,特殊的方法隱含調用是只能保證正常工作,如果一個對象的類型定義,而不是在對象的實例字典。

請按照鏈接瞭解這背後的基本原理。我理解的基本思想是,適用於實例對象和類型對象(如__repr__)的特殊方法需要一致調用,而不是有時需要顯式參數,有時需要接收隱式參數。通過始終調用對象類型的方法,我們知道總是傳遞一個明確的參數 - 但副作用是實例字典被繞過。

+0

請注意,這明確地說「新風格的類」,而OP在他的示例中有一箇舊式類 – lqc

3

它記錄在Data model,部分「類實例」:

屬性分配和刪除更新實例的字典裏,從來沒有 類的字典。 如果類有一個__setattr__()__delattr__()方法,則調用此方法而不是直接更新實例字典。

因此,無論是舊式還是新式,這兩種檢查總是在類型上進行,而不是在實例上進行。

+0

謝謝,我確實看了一下Data模型,但我錯過了那部分。那麼我在我發佈的代碼中看到的行爲就很有道理。也許一個愚蠢的問題:當它說「如果這個類有一個__setattr__」,那麼這個負面可能性實際上是否存在?是否有可能創建一個沒有__setattr__的類? – Spock