我的应用依赖于list
和dict
数据结构来维护当前状态。现在我需要跟踪从列表中添加/删除元素或dict数据更改的时间。我用谷歌搜索并发现有collections.abc.Sequence
(列表)和collections.abc.MutableMapping
(对于dict),但它们非常有限,结果不能用来代替list / dict({ {1}},append
,...)。我一直在考虑一些代理类,它会转发调用并提供在某些方法被转发之前/之后调用的钩子,但是没有找到任何甚至看起来像的东西。
所以我的问题是:如何挂钩给定结构的变异器?有什么我不知道的吗?
答案 0 :(得分:5)
即使正式支持子类化内置类,我仍然建议您考虑使用代理类。
问题是调用overriden方法时没有详细记录。例如,如果您覆盖__setitem__
方法,则在使用extend
方法修改字典时不会调用它,例如mydict.extend({"a": 42})
。您还必须覆盖extend
。很容易忘记覆盖一些模糊的方法,并且在没有调用回调的情况下静默进行修改(而如果你使用代理,它会抛出一个AttributeError
,表明你忘了定义一些方法)。 / p>
还有更多。一些通过参数接收字典的内置方法在CPython中根本不会调用任何覆盖方法,如下面的example from PyPy wiki所示:
>>>> class D(dict):
.... def __getitem__(self, key):
.... return 42
....
>>>>
>>>> d1 = {}
>>>> d2 = D(a='foo')
>>>> d1.update(d2)
>>>> print d1['a']
foo # but 42 in PyPy
答案 1 :(得分:4)
子类化dict可能:
class DictWatch(dict):
def __init__(self, *args, **kwargs):
self.callback = kwargs.pop('callback')
dict.__init__(self, args)
def __setitem__(self, key, val):
# YOUR HOOK HERE
self.callback(key, val)
dict.__setitem__(self, key, val)
# and other overrided dict methods if you need them
演示:
>>> def cb(k,v):
... print k,v
...
>>> d=DictWatch(callback=cb)
>>> d['key']='100'
key 100
答案 2 :(得分:0)
使用hooky,http://hooky.readthedocs.com
hooky.List
的示例:
#!/usr/bin/env python
from hooky import List
class MyList(List):
def _before_add(self, key, item):
print('before add, key: {}, item: {}'.format(key, repr(item)))
def _after_add(self, key, item):
print(' after add, key: {}, item: {}'.format(key, repr(item)))
def _before_del(self, key):
print('before_del, key: ', key)
def _after_del(self, key):
print(' after_del, key: ', key)
l = MyList(['a', 'b'])
l.append(1)
l.extend(['f', 'g', 2])
l.pop()
l[2:3] = ['c', 'd', 'e']
print(l)
l.clear()
print(l)
打印出来:
before add, key: 0, item: 'a'
after add, key: 0, item: 'a'
before add, key: 1, item: 'b'
after add, key: 1, item: 'b'
before add, key: 2, item: 1
after add, key: 2, item: 1
before add, key: 3, item: 'f'
after add, key: 3, item: 'f'
before add, key: 4, item: 'g'
after add, key: 4, item: 'g'
before add, key: 5, item: 2
after add, key: 5, item: 2
before_del, key: -1
after_del, key: -1
before_del, key: 2
after_del, key: 2
before add, key: 2, item: 'c'
after add, key: 2, item: 'c'
before add, key: 3, item: 'd'
after add, key: 3, item: 'd'
before add, key: 4, item: 'e'
after add, key: 4, item: 'e'
['a', 'b', 'c', 'd', 'e', 'f', 'g']
before_del, key: -1
after_del, key: -1
before_del, key: -1
after_del, key: -1
before_del, key: -1
after_del, key: -1
before_del, key: -1
after_del, key: -1
before_del, key: -1
after_del, key: -1
before_del, key: -1
after_del, key: -1
before_del, key: -1
after_del, key: -1
[]