2014-10-28 73 views
4

我有一個很大的2D(列表列表)列表,每個元素包含一個int列表,字符串和字典。我希望能夠在修改過的任何元素上確定'路徑'(例如[2] [3] [2] [「項目」] [2]!) 。這個列表是爲了大掃描,看看發生了什麼變化!理想情況下,我也想要一個新元素的副本,儘管這可以在稍後找到。如何檢測嵌套列表的哪些元素已更改? (python)

我的第一次嘗試是創建一個類,並覆蓋其__setattr__方法:

class Notify(): 
    def __setattr__(self, name, value): 
     self.__dict__[name] = value  #Actually assign the value 
     print name, value     #This will tell us when it fires 

然而,__setattr__方法設置不是由索引(或鍵)來訪問一個變量時僅火災,因爲這似乎將該調用外包給包含的list()/ dict()類而不是我們的類。

>>> test = Notify() 
>>> test.var = 1   #This is detected 
var 1 

>>> test.var = [1,2,3] #Now let's set it to a list 
var [1, 2, 3]    

>>> test.var[0] = 12  #But when we assign a value via an index, it doesn't fire 
>>> test.var 
[12, 2, 3]    #However it still assigns the value, so it must be talking to the list itself! 

因此,要總結,我想(真的任何方法),告訴我什麼(索引/鍵列表)發生了變化,這需要,因爲它發生的情況發生,因爲它太昂貴掃描整個列表。我也不能依靠修改列表來提供細節的代碼。如果這對於第n個嵌套列表是不可能的,那麼我可以使用只給出前兩個索引的東西,因爲數據不會太大而無法掃描。預先感謝您的幫助!

編輯:仍然沒有快樂,雖然這個問題Track changes to lists and dictionaries in python?似乎接近我所需要的。不幸的是,我對班級不太好,需要某個人的幫助!

編輯:看看這個Python: Right way to extend list讓我覺得繼承list可能是一個壞主意。我使用代理類代替了以下代碼。但是原始問題仍然存在,對嵌套列表的修改不會記錄。班級構成,而不是繼承是一個好主意?

from UserList import UserList 

class NotifyList(UserList): 

    def __init__(self, initlist=None): 
     self.data = [] 
     if initlist is not None: 
      if type(initlist) is list: 
       self.data[:] = initlist 
      elif isinstance(initlist, NotifyList): 
       self.data[:] = initlist.data[:] 
      else: 
       self.data = list(initlist) 

    def __setitem__(self, key, item): 
     if type(item) is list: 
      self.data[key] = NotifyList(item) 
     else: 
      self.data[key] = item 
     print key, item 

    def append(self, item): 
     if type(item) is list: 
      self.data.append(NotifyList(item)) 
     else: 
      self.data.append(item) 
     print self.index(item), item 
+1

也許你可以檢查'__setattr__'的值的類型,如果它是一個列表,你可以把它包裝在一個通知對象? – lelloman 2014-10-28 12:11:59

+0

此外,您可以添加一些功能以通知類,如父級,所以如果值更改,並且Notify類不是根可以向上傳遞事件 – lelloman 2014-10-28 12:15:29

+0

也許[this](http://stackoverflow.com/問題/ 8858525/track-changes-to-lists-and-dictionaries-in-python)答案可能對你有所幫助。 – 2014-10-28 12:17:17

回答

1

您需要在可跟蹤列表的列表(可追蹤)中創建一個報告鏈,其中每個列表都會向其父級報告修改。在您的NotifyList類中,爲父項添加一個參數,併爲父項知道新項目的ID添加一個參數 - 父項爲列表時,這將成爲列表索引:

class NotifyList(UserList): 
    def __init__(self, inilist=None, parent=None, id=None): 
     self.parent = parent 
     self.id = id 
     # remainder of __init__()... 

當修改發生時,應通知家長。例如,在__setitem__

def __setitem__(self, key, item): 
    if type(item) is list: 
     self.data[key] = NotifyList(item, self, str(key)) # Don't forget the new item's parent 
    else: 
     self.data[key] = item 
    self.alertParent(str(key), str(item)) # Report up the chain instead of printing 

alertParent()是:

def alertParent(self, key, item): 
    strChange = "[{0}] = {1}".format(key, item) 
    self.parent.notifyChange(self.id, strChange) 

如何notifyChange()工作?

def notifyChange(self, childKey, strChangeInChild): 
    strChange = "[{0}]{1}".format(childKey, strChangeInChild) 
    self.parent.notifyChange(self.id, strChange) 

它只是傳播通知上鍊,添加自己的ID到消息。

唯一缺失的鏈接是,報告鏈頂部發生了什麼?最終應該打印更改消息。下面是一個簡單的伎倆重用alertParent()來實現:

def alertParent(self, key, item): 
    if self.parent is None: # I am the root 
     print "[{0}]{1}".format(key, item) 
    else: 
     # remainder of alertParent() shown above... 
... 
def notifyChange(self, childKey, strChangeInChild): 
    if self.parent is None: # I am the root 
     self.alertParent(childKey, strChangeInChild) # Actually just prints a change msg 
    else: 
     # remainder of notifyChange() shown above... 

我編寫這件事,完整版本可here [谷歌文檔(有一對夫婦對於瑣碎的bug修復什麼,我已經提出了以上)。在行動:

>>> from test import NotifyList 
>>> top = NotifyList([0]*3, None, None) # Now we have [0 0 0] 
>>> print top 
NList-[0, 0, 0] 

>>> top[0] = NotifyList([0]*3, top, 0) # Now we have [ [0 0 0] 0 0 ] 
[0] = NList-[0, 0, 0] #-------------- The tracking msg is fired 

>>> print top 
NList-[<test.NotifyList object at 0x0000000002163320>, 0, 0] 

>>> top[0][1] = NotifyList([0]*3, top[0], 1) # Now we have [ [[0 0 0] 0 0] 0 0 ] 
[0][1] = NList-[0, 0, 0] #----------- The tracking msg fired again 

>>> top[0][1][2] = "this is a string" # Now we have [ [[0 0 "this is a string] 0 0] 0 0 ] 
[0][1][2] = this is a string #------- And another tracking msg 

>>> print top[0][1][2] 
this is a string 

>>> print top[0][1] 
NList-[0, 0, 'this is a string'] 
相關問題