跟踪python中列表和字典的更改?

发布于 2021-01-29 17:23:30

我有一个此类的实例需要跟踪其属性更改的类。

例如:obj.att = 2将东西是很容易可追踪通过简单地重写__setattr__obj

但是,当我要更改的属性是对象本身(如列表或字典)时,就会出现问题。

我将如何跟踪类似obj.att.append(1)或的信息obj.att.pop(2)

我正在考虑扩展列表或字典类,但是一旦objobj.att都被初始化,猴子会修补这些类的实例,以便obj.append调用诸如此类的东西时得到通知。不知何故,那感觉并不十分优雅。

我能想到的另一种方法是将实例传递obj到列表初始化中,但这会破坏很多现有代码,而且看起来甚至比以前的方法还不够优雅。

还有其他想法/建议吗?我在这里缺少一个简单的解决方案吗?

关注者
0
被浏览
47
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    当我看到问题时,我很好奇这将如何完成,这是我想出的解决方案。虽然不像我希望的那么简单,但是它可能会有用。首先,这是行为:

    class Tracker(object):
        def __init__(self):
            self.lst = trackable_type('lst', self, list)
            self.dct = trackable_type('dct', self, dict)
            self.revisions = {'lst': [], 'dct': []}
    
    
    >>> obj = Tracker()            # create an instance of Tracker
    >>> obj.lst.append(1)          # make some changes to list attribute
    >>> obj.lst.extend([2, 3])
    >>> obj.lst.pop()
    3
    >>> obj.dct['a'] = 5           # make some changes to dict attribute
    >>> obj.dct.update({'b': 3})
    >>> del obj.dct['a']
    >>> obj.revisions              # check out revision history
    {'lst': [[1], [1, 2, 3], [1, 2]], 'dct': [{'a': 5}, {'a': 5, 'b': 3}, {'b': 3}]}
    

    现在trackable_type(),使所有这些变为可能的函数:

    def trackable_type(name, obj, base):
        def func_logger(func):
            def wrapped(self, *args, **kwargs):
                before = base(self)
                result = func(self, *args, **kwargs)
                after = base(self)
                if before != after:
                    obj.revisions[name].append(after)
                return result
            return wrapped
    
        methods = (type(list.append), type(list.__setitem__))
        skip = set(['__iter__', '__len__', '__getattribute__'])
        class TrackableMeta(type):
            def __new__(cls, name, bases, dct):
                for attr in dir(base):
                    if attr not in skip:
                        func = getattr(base, attr)
                        if isinstance(func, methods):
                            dct[attr] = func_logger(func)
                return type.__new__(cls, name, bases, dct)
    
        class TrackableObject(base):
            __metaclass__ = TrackableMeta
    
        return TrackableObject()
    

    基本上,这使用元类重写对象的每个方法,以在对象更改时添加一些修订日志。这没有经过全面的测试,除了list和之外,我还没有尝试过其他任何对象类型dict,但是对于这些对象似乎还可以。



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看