2012-05-17 70 views
4

有沒有辦法在python中覆蓋內置類型的特殊功能?例如,我想創建一個從內置字典繼承的SpecialDict類。我希望允許用戶定義自定義的驗證功能,在我的特殊字典key和值,就像這樣:在Python中覆蓋特殊功能

def __init__(self, keyValidator = True, valueValidator = True): 
    self.keyValidator = keyValidator 
    self.valueValidator = valueValidator 

利用這一點,我可以攔截在更新方法中添加值,就像這樣:

def update(self,key,value): 
    assert (self.keyValidator(key)) 
    assert (self.valueValidator(key)) 
    self[key] = value 

但是,如果有人決定繼續使用[]作爲訪問權限,這將無法正常工作。或者如果有人使用字典文字創建對象。

mySpecialDict = SpecialDict 
mySpecialDict['hello'] = 54 
+0

幾乎所有您看到標準對象支持的語法都可以通過Python手動實現。他們的網站上有關於此事的豐富文檔。 – slezica

回答

4

有人無法創建SpecialDict的實例作爲一個字典文字,因爲文字的字典就是這樣;一個正常的字典。

只要設置帶方括號的項目,如mySpecialDict['hello'] = 54,就是mySpecialDict.__setitem__('hello', 54)。同樣,使用方括號表示法檢索項目對應於調用__getitem__方法。無論mySpecialDict是什麼類別,情況都是如此;無論是普通字典,內建dict的類,還是一些完全不相關的類。所以你可以實現這些方法來改變它們的作用(當你需要時,使用super(SpecialDict, self).__setitem__(key, value)dict.__setitem__(self, key, value)來引用正常的實現)。

您會遇到的一個問題是其他字典方法的內置實現的一些(全部?)將不會尊重您重寫的__setitem____getitem__。所以你將無法繼承它們;你必須重寫所有這些,或者根據你的基本操作版本完全重新實現它們,或者至少在超類調用的「周圍」運行你的驗證。

一個更麻煩的辦法實際上可能是子內置的字典,而是實現一個自定義的「字典式」對象包裝一個普通的字典,使用collections.Mappingcollections.MutableMapping基類來獲得字典界面。使用這種方法,你只需要自己實現大約6個基本方法(你可以通過在包裝字典的調用中插入驗證邏輯來​​實現),並根據它們獲取其他方法的合理定義。請參閱http://docs.python.org/library/collections.html#collections-abstract-base-classes

+0

感謝您的深入解答。它回答了我的問題並且診斷了我的潛在問題。 – kumikoda

2

您可以覆蓋特殊的方法__getitem__實現自己的[]運營商的行爲。有關更多信息,請參閱this

+2

最好在你的答案中加入'__setitem__'和'__missing__'方法。 – rantanplan

0

雷霆!

我在移動設備中,從而將不能夠給出一個完整的答案,但查找__getitem____setitem__

0

您可以覆蓋__setitem__(self, key, val)方法,並使用super(SpecialDict, self).__setitem__訪問父對象的(即dict S)方法:

class SpecialDict(dict): 
    def __init__(self, keyValidator = lambda x:True, valueValidator = lambda x:True): 
     self.keyValidator = keyValidator 
     self.valueValidator = valueValidator 
    def __setitem__(self, key, val): 
     assert (self.keyValidator(key)) 
     assert (self.valueValidator(val)) 
     super(SpecialDict, self).__setitem__(key, val) 

也請注意用lambdas爲默認值:使用簡單TrueFalse將導致錯誤,因爲他們是不可調用的。