如何检测嵌套列表中的哪个元素发生了更改?(Python)

2024-03-29 14:37:33 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个大的2D(列表列表)列表,每个元素都包含一个int、字符串和dict的列表。我希望能够确定“路径”(例如[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()类,而不是我们的类。在

^{pr2}$

所以,总而言之,我想要(任何一种方法)告诉我在什么地方(索引/键列表)发生了变化,这需要在发生时发生,因为扫描整个列表太昂贵了。我也不能依赖修改列表的代码来提供详细信息。如果这对于第n个嵌套列表是不可能的,我可以使用只给出前两个索引的东西,因为那里的数据不会太大而无法扫描。提前感谢您的帮助!在

编辑:还是不高兴,虽然这个问题似乎很接近我需要的。不幸的是,我不太擅长上课,需要有人帮我!在

编辑:看看这个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

Tags: 方法keyself列表dataifisvalue
2条回答

我的jsonfile模块检测(嵌套的)JSON兼容Python对象的更改。只需子类JSONFileRoot就可以根据需要调整变更检测。在

>>> import jsonfile
>>> class Notify(jsonfile.JSONFileRoot):
...   def on_change(self):
...     print(f'notify: {self.data}')
... 
>>> test = Notify()
>>> test.data = 1
notify: 1
>>> test.data = [1,2,3]
notify: [1, 2, 3]
>>> test.data[0] = 12
notify: [12, 2, 3]
>>> test.data[1] = {"a":"b"}
notify: [12, {'a': 'b'}, 3]
>>> test.data[1]["a"] = 20
notify: [12, {'a': 20}, 3]

您需要在可跟踪列表的(可跟踪)列表中创建一个报告链,其中每个列表向其父列表报告修改。在您的NotifyList类中,向构造函数添加一个父对象的参数和一个标识的参数,当父对象是一个列表时,父对象将通过该参数知道新项,这将是一个列表索引:

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

当修改发生时,应通知家长。例如__setitem__

^{pr2}$

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[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']

相关问题 更多 >