Python 3:钩子列表&;口述变化
我的应用程序依靠Python 3:钩子列表&;口述变化,python,python-3.x,hook,Python,Python 3.x,Hook,我的应用程序依靠list和dict数据结构来维护当前状态。现在我需要跟踪元素在列表中的添加/删除或dict数据更改。我在谷歌上搜索发现有collections.abc.Sequence(用于列表)和collections.abc.MutableMapping(用于dict),但它们非常有限,结果不能代替list/dict(append,clear,…)。我一直在考虑一些代理类,它将转发调用,并在转发某个方法之前/之后提供要调用的挂钩,但在中找不到任何类似的 所以我的问题是:如何钩住给定结构的变异
list
和dict
数据结构来维护当前状态。现在我需要跟踪元素在列表中的添加/删除或dict数据更改。我在谷歌上搜索发现有collections.abc.Sequence
(用于列表)和collections.abc.MutableMapping
(用于dict),但它们非常有限,结果不能代替list/dict(append
,clear
,…)。我一直在考虑一些代理类,它将转发调用,并在转发某个方法之前/之后提供要调用的挂钩,但在中找不到任何类似的
所以我的问题是:如何钩住给定结构的变异子?有什么我不知道的吗?子类化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
演示:
尽管正式支持子类内置类,但我还是建议您考虑使用代理类。
问题是调用重写的方法时没有很好的文档记录。例如,如果重写\uuuu setitem\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
方法,则当您使用。您还必须覆盖扩展。很容易忘记覆盖一些模糊的方法,修改将在不调用回调的情况下悄无声息地进行(而如果使用代理,它将抛出一个AttributeError
,指示您忘记定义某个方法)
还有更多。某些通过参数接收字典的内置方法在CPython中根本不会调用任何重写的方法,如下所示:
逃学
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
[]
我想到的唯一方法是自己实现list/dict的子类,然后重写append
、clear
等。我看到一些讨论指出继承内置类型是个坏主意。还是错了?@Daniel:从内置类型继承绝对没有错!那太傻了。
#!/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
[]