2009-06-09 54 views
4

我想創建一個基本上是樣本列表的DataSet類。 但我需要重寫DataSet的每個插入操作。子類列表

有沒有簡單的方法來做到這一點,而不寫我自己的追加,擴展,iadd等?

UPDATE:我想爲每個樣本添加一個反向指針,持有DataSet中樣本的索引。這是我使用的處理算法所需要的。我有一個解決方案,但它看起來不合格 - 一個renumber()函數 - 它確保了後向指針是有效的。

+0

亞歷克斯回答說,這似乎很難。但是,如果你向我們解釋什麼應該重寫插入,人們可能會想出一個優雅的解決方案。 – NicDumZ 2009-06-09 14:45:24

+0

我想他是指猴子補丁。 – Geo 2009-06-09 14:52:42

回答

5

我不知道有什麼方法來做你想問的 - 覆蓋mutators而不會覆蓋它們。然而,使用類裝飾器,您可以「自動化」壓倒一切的版本(假設每個版本都可以通過在基類中包裝相應的方法來實現),所以它並不算太壞...

假設例如你想要做的是添加一個「修改」標誌,如果數據可能自上次調用.save(您持有數據並將self.modified設置爲False)的方法發生更改,則爲true。

然後...:

def wrapMethod(cls, n): 
    f = getattr(cls, n) 
    def wrap(self, *a): 
     self.dirty = True 
     return f(self, *a) 
    return wrap 

def wrapListMutators(cls): 
    for n in '''__setitem__ __delitem__ __iadd__ __imul__ 
       append extend insert pop remove reverse sort'''.split(): 
    f = wrapMethod(cls, n) 
    setattr(cls, n, f) 
    return cls 

@wrapListMutators 
class DataSet(list): 
    dirty = False 
    def save(self): self.dirty = False 

這句法需要Python 2.6或更好,但是,在早期版本的Python(那些只支持def陳述裝飾,而不是class報表;甚至很舊的不支持在裝飾全部),你只需要改變的最後部分(class語句),以:

class DataSet(list): 
    dirty = False 
    def save(self): self.dirty = False 
DataSet = wrapListMutators(DataSet) 

督察,整齊的裝飾語法是在上面的語法糖只是少量一個正常的函數調用,它將類作爲參數並重新分配它。

編輯:現在你已經編輯了自己的問題,以澄清自己的實際需要 - 在每個項目上保持着場bp這樣,對於所有itheset[i].bp == i - 它更容易衡量親和的各種方法CON。

你能適應我勾勒的辦法,但不是在調用包裝方法之前self.dirty分配,有self.renumber()電話後,即:

def wrapMethod(cls, n): 
    f = getattr(cls, n) 
    def wrap(self, *a): 
     temp = f(self, *a) 
     self.renumber() 
     return temp 
    return wrap 

這符合你們所要求的,但在許多它會做的工作遠遠超過必要的工作:例如,當你一個項目,這不必要地「重新編號」所有現有的(與他們已有的相同的值)。但是如何完全自動化的方法「知道」哪些項目,如果有的話,它必須重新計算.bp,而不需要O(N)的努力?至少它必須看看它們中的每一個(因爲你不想單獨編碼,例如,append vs insert & c),並且這已經是O(N)

因此,只有當列表中的每一次更改都可以使用O(N)(基本上只有在列表總是保持較小和/或不經常更改的情況下)時,纔可以接受。

更有成效的想法可能是始終不維護.bp值,但只在需要時才「及時」。使bp成爲一個(只讀)屬性,調用一個方法來檢查容器是否「髒」(使用我已經提供的自動化代碼來維護容器中的「髒」標誌),然後只對容器重新編號(並將其「髒」屬性設置爲False)。

當列表通常受到突發變化影響時,此功能將正常工作,只有當您需要訪問項目bp一段時間,然後再進行另一些更改等操作時,此類突發變化纔會發生變化。在現實世界的容器中並不罕見,但只有您可以知道它是否適用於您的特定情況!

爲了獲得超出這個性能,我認爲您需要在這種通用方法的基礎上手動編碼以利用頻繁的特殊情況。例如,append可能會經常被調用,並且在特殊情況下執行的工作量非常小,所以編寫這兩行或三行代碼(不設置髒位對於那種情況)。

一個告誡:如果任何項目在列表中出現兩次,則沒有任何方法可行(實際上您的需求會自相矛盾) - 除非您採取預防措施以避免它,否則這當然是完全可能的(您可以輕鬆地診斷renumber - 通過保留已經看到的一組元素,並在任何重複上引發異常 - 如果對您來說還不算太晚;「動態」診斷就更難了,即在發生導致重複,如果這是你需要的)。也許你可以放鬆你的要求,如果一件物品出現兩次,那沒關係,並且bp可以指示其中的一個指數;或者將bp變成集合其中存在元素的索引(這也將提供平滑的方法來從而不是的元素獲得bp的情況)。等等;我建議你考慮(和文檔!)所有這些角落案例的深度 - 表現之前的正確性!