2014-10-28 54 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'] 
相关问题