Python 3:钩子列表和字典变化

Dan*_*iel 3 python hook python-3.x

我的应用程序依赖于listdict数据结构保持当前状态.现在我需要跟踪从列表中添加/删除元素或dict数据更改的时间.我一派,并发现有collections.abc.Sequence(用于列表)和collections.abc.MutableMapping(对于字典),但他们是非常有限的,因此不能用来代替列表/字典(append,clear,...).我一直在考虑一些代理类,它会转发调用并提供在某些方法被转发之前/之后调用的钩子,但是没有找到任何甚至看起来像的东西.

所以我的问题是:如何挂钩给定结构的变异器?有什么我不知道的吗?

ndp*_*dpu 5

子类化字典可能:

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)


WGH*_*WGH 5

即使正式支持子类化内置类,我仍然建议您考虑使用代理类.

问题是,在调用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)