Python 3:钩子列表& dict变化

时间:2014-02-02 11:50:11

标签: python python-3.x hook

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

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

3 个答案:

答案 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
[]