我有一个很大的2D(列表列表)列表,每个元素都包含一个整数,字符串和字典的列表。我希望能够确定任何已修改元素的“路径”(例如,[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, 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个嵌套列表是不可能的,那么我可以使用仅给出前两个索引的东西,因为数据不会太大而无法扫描。预先感谢您的帮助!
编辑:仍然没有喜悦,尽管此问题跟踪更改为python中的列表和词典?似乎与我需要的接近。不幸的是,我在课堂上的表现不是很好,需要别人的帮助!
编辑:看过这个Python:扩展列表的正确方法让我想到继承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, 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...
我对此进行了编码,完整版本可在[Google Doc]中找到(相对于我在上面介绍的内容,有一些小错误修复)。在行动中:
>>> 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']
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句