gpt4 book ai didi

python - Dictionary子类,所有的编辑方法都被回调覆盖了吗?

转载 作者:太空宇宙 更新时间:2023-11-03 15:07:53 25 4
gpt4 key购买 nike

我想要一个处理字典的函数,像字典或类似的那样处理,只需很少的工作,这样当调用时我就可以运行其他代码。

我认为对 dict 进行子类化似乎更容易,所以我这样做了。通过阅读 help(dict) 我认为我已经涵盖了所有字典编辑功能,因此也可以调用回调。我有没有?还有其他像 pop 一样返回编辑值的吗?

class BindedDict(dict):
"""Custom dictionary with callback when edited."""

def __init__(self, callback, *a, **kw):
self.callback = callback
super().__init__(*a, *kw)
return

def __delitem__(self, *a, **kw):
super().__delitme__(*a, **kw)
self.callback()
return

def __setitem__(self, *a, **kw):
super().__setitem__(*a, **kw)
self.callback()
return

def clear(self, *a, **kw):
super().clear(*a, **kw)
self.callback()
return

def pop(self, *a, **kw):
r = super().pop(*a, **kw)
self.callback()
return r

def popitem(self, *a, **kw):
super().popitem(*a, **kw)
self.callback()
return

def setdefault(self, *a, **kw):
super().setdefault(*a, **kw)
self.callback()
return

def update(self, *a, **kw):
super().update(*a, **kw)
self.callback()
return

还有一个更好的标题和类名会更好。

最佳答案

我会使用组合而不是继承,并实现 MutableMapping来自 collections.abc 这样我就可以免费获得一些实现的方法。根据文档,您必须提供 __getitem__ 的实现, __setitem__ , __delitem__ , __iter__ ,和__len__ :

from collections.abc import MutableMapping


class BoundDict(MutableMapping):
"""Dict-like class that calls a callback on changes.

Note that the callback is invoked *after* the
underlying dictionary has been mutated.

"""

def __init__(self, callback, *args, **kwargs):
self._callback = callback
self._map = dict(*args, **kwargs)

def __getitem__(self, key):
return self._map[key]

def __setitem__(self, key, value):
self._map[key] = value
self._callback()

def __delitem__(self, key):
del self._map[key]
self._callback()

def __iter__(self):
return iter(self._map)

def __len__(self):
return len(self._map)

请注意,您不需要放置裸露的 return在方法的末尾,我添加了一个文档字符串来解释该类的作用。

感谢抽象基类,现在将为您实现以下附加方法:__contains__ , keys , items , values , get , __eq__ ,和__ne__ , pop , popitem , clear , update ,和setdefault 。因为它们都调用上面定义的五个基本方法,所以可以保证通过 MutableMapping 进行任何更改。接口(interface)(尽管直接更改为 _map)将调用回调,因为它总是涉及调用 __setitem____delitem__ .

使用中:

>>> bd = BoundDict(lambda: print('changed'), [('foo', 'bar')], hello='world')
>>> bd
<BoundDict object at 0x7f8a4ea61048>
>>> list(bd.items())
[('foo', 'bar'), ('hello', 'world')]
>>> bd['foo']
'bar'
>>> bd['hello']
'world'
>>> bd['foo'] = 'baz'
changed
>>> del bd['hello']
changed
>>> bd['foo']
'baz'
>>> bd['hello']
Traceback (most recent call last):
File "python", line 1, in <module>
File "python", line 16, in __getitem__
KeyError: 'hello'

这样做的唯一缺点是,如果您进行显式类型检查,则可能会遇到问题:

>>> isinstance(bd, dict)
False

但是,您通常也应该使用 ABC 进行类型检查(或只是 duck typing ):

>>> isinstance(bd, MutableMapping)
True
>>> isinstance(dict(), MutableMapping)
True
<小时/>

我认为,当您问“这可以解释为什么我在示例中只看到一个回调?” below您想知道为什么我们的不同实现会发生以下情况:

>>> BindedDict(lambda: print('changed'), foo='bar', hello='world').clear()
changed
>>> BoundDict(lambda: print('changed'), foo='bar', hello='world').clear()
changed
changed

这是由于 MutableMapping.clear 的实现;它循环遍历字典中的键,调用 popitem对于每一个,依次调用 __delitem__ ,这又调用回调。相比之下,您的实现仅调用回调一次,因为您实现了 clear直接并从那里调用它。

请注意,ABC 方法不会阻止您这样做。从您的问题中尚不清楚(您可能还不知道)哪种行为是正确的,但您仍然可以进来并覆盖 ABC 提供的默认实现:

class BoundDict(MutableMapping):
"""..."""

...

def clear(self):
self._map.clear() # or e.g. self._map = {}
self._callback()

我建议使用 ABC 而不是子类化的原因 dict的一点是,这为您提供了合理的默认实现,您可以在需要的地方覆盖它们,因此您只需担心您的行为与默认值的不同之处。实现的方法越少,也意味着像__delitme__这样的简单拼写错误的风险更小。 (如果您不提供必需的 @abstractmethod,当您尝试实例化该类时,您会收到错误)和 super().__init__(*a, *kw) .

关于python - Dictionary子类,所有的编辑方法都被回调覆盖了吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44478363/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com