Dan*_*iel 3 python hook python-3.x
我的应用程序依赖于list
与dict
数据结构保持当前状态.现在我需要跟踪从列表中添加/删除元素或dict数据更改的时间.我一派,并发现有collections.abc.Sequence
(用于列表)和collections.abc.MutableMapping
(对于字典),但他们是非常有限的,因此不能用来代替列表/字典(append
,clear
,...).我一直在考虑一些代理类,它会转发调用并提供在某些方法被转发之前/之后调用的钩子,但是没有找到任何甚至看起来像的东西.
所以我的问题是:如何挂钩给定结构的变异器?有什么我不知道的吗?
子类化字典可能:
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
Run Code Online (Sandbox Code Playgroud)
演示:
>>> def cb(k,v):
... print k,v
...
>>> d=DictWatch(callback=cb)
>>> d['key']='100'
key 100
Run Code Online (Sandbox Code Playgroud)
即使正式支持子类化内置类,我仍然建议您考虑使用代理类.
问题是,在调用overriden方法时没有详细记录.例如,如果覆盖__setitem__
方法,则在使用extend
方法修改dict时不会调用它,例如mydict.extend({"a": 42})
.你也必须覆盖extend
.很容易忘记覆盖一些模糊的方法,并且在没有调用回调的情况下静默地进行修改(而如果你使用代理,它会抛出一个AttributeError
表明你忘了定义某个方法).
还有更多.一些通过参数接收字典的内置方法在CPython中根本不会调用任何重写方法,如以下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
Run Code Online (Sandbox Code Playgroud)