如何检测嵌套列表的哪个元素已更改? (Python)
我有一个大的2D(列表列表)列表,每个元素包含一个int,字符串和dicts列表.我希望能够确定任何修改过的元素的’路径'(例如[2] [3] [2] [“items”] [2]!) .这个列表很大,可以浏览并查看更改内容!理想情况下,我也想要一个新元素的副本,虽然这可以在以后找到.
我的第一次尝试是创建一个类,并覆盖其__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,3] >>> test.var[0] = 12 #But when we assign a value via an index,it doesn't fire >>> test.var [12,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让我觉得继承列表可能是一个坏主意.我使用代理类代替了以下代码.然而,最初的问题仍然存在,对嵌套列表的修改不会记录.课堂作文,而不是继承是一个好主意吗? 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 解决方法
您需要在(可跟踪)可跟踪列表列表中创建报告链,其中每个列表都会报告对其父级的修改.在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,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,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,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,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 [Google Doc](关于我上面提到的内容,有几个简单的bug修复).在行动: >>> from test import NotifyList >>> top = NotifyList([0]*3,None,None) # Now we have [0 0 0] >>> print top NList-[0,0] >>> top[0] = NotifyList([0]*3,top,0) # Now we have [ [0 0 0] 0 0 ] [0] = NList-[0,0] #-------------- The tracking msg is fired >>> print top NList-[<test.NotifyList object at 0x0000000002163320>,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] #----------- 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,'this is a string'] (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |