跟踪python中列表和字典的更改?
我有一个此类的实例需要跟踪其属性更改的类。
例如:obj.att = 2
将东西是很容易可追踪通过简单地重写__setattr__
的obj
。
但是,当我要更改的属性是对象本身(如列表或字典)时,就会出现问题。
我将如何跟踪类似obj.att.append(1)
或的信息obj.att.pop(2)
?
我正在考虑扩展列表或字典类,但是一旦obj
和obj.att
都被初始化,猴子会修补这些类的实例,以便obj
在.append
调用诸如此类的东西时得到通知。不知何故,那感觉并不十分优雅。
我能想到的另一种方法是将实例传递obj
到列表初始化中,但这会破坏很多现有代码,而且看起来甚至比以前的方法还不够优雅。
还有其他想法/建议吗?我在这里缺少一个简单的解决方案吗?
-
当我看到问题时,我很好奇这将如何完成,这是我想出的解决方案。虽然不像我希望的那么简单,但是它可能会有用。首先,这是行为:
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
,但是对于这些对象似乎还可以。