我正在尝试创建一个字典子类,该子类允许创建字典A,该字典将更新预先存在的字典B中的值,使其等于字典A的字符串表示形式。我将其视为观察者模式,而没有具有观察多个物体的能力。
即:
import json
from collections import Mapping
class ObservedDict(dict):
def __init__(self, initial_dict, name=None, observer=None, top_level=True):
for k, v in initial_dict.items():
if isinstance(v, dict):
initial_dict[k] = ObservedDict(v, name, observer, top_level=False)
super().__init__(initial_dict)
self.name = name
self.observer = observer
if top_level is True: # initialise the key:value pair in B
observer[name] = json.dumps(initial_dict)
def __setitem__(self, item, value):
if isinstance(value, dict):
_value = ObservedDict(value, self.name, self.observer, top_level=False)
else:
_value = value
super().__setitem__(item, _value)
# Update B
self.observer[self.name] = json.dumps(self)
B = {}
A = ObservedDict({'foo': 1, 'bar': {'foobar': 2}}, 'observed', B)
B现在为{'observed': '{"foo": 1, "bar": {"foobar": 2}}'}
,A为{'foo': 1, 'bar': {'foobar': 2}}
。在三种情况下,更新字典中的值(暂时忽略update
和set
):
A['foo'] = 2
# B is now automatically {'observed': '{"foo": 2, "bar": {"foobar": 2}}'}
A['bar'] = {'foobar': 4}
# B is now automatically {'observed': '{"foo": 2, "bar": {"foobar": 4}}'}
[]
方法编辑嵌套值,则self
中的__setitem__
是嵌套字典,而不是ObservedDict
类所使用的整个字典已初始化,所以:A['bar']['foobar'] = 4
# B is now {'observed': '{"foobar": 4}'}
我的问题是:如何保留有关父词典(即用于初始化类的信息)的信息,以便在使用第三种情况设置值时,词典B
将更新并包括整个字典A(在这种情况下,匹配情况2)?
答案 0 :(得分:0)
好的,所以尽管我以前曾尝试过将父词典附加到嵌套字典上,但没有运气,@ MichaelButscher的评论促使我再试一次。以下是一个可行的解决方案,无论深度如何,该解决方案似乎都可以使用[]
方法在嵌套字典中设置值。
import json
from collections import Mapping
class ObservedDict(dict):
def __init__(self, initial_dict, name=None, observer=None, parent=None):
for k, v in initial_dict.items():
if isinstance(v, dict):
_parent = self if parent is None else parent
initial_dict[k] = ObservedDict(v, name, observer, parent=_parent)
super().__init__(initial_dict)
self.observer = observer
self.name = name
self.parent = parent
if parent is None: # initialise the key:value pair in B
observer[name] = json.dumps(initial_dict)
def __setitem__(self, item, value):
if isinstance(value, dict):
_value = ObservedDict(value, self.name, self.observer, parent=self.parent)
else:
_value = value
super().__setitem__(item, _value)
# Update B
if self.parent is not None:
self.observer[self.name] = json.dumps(self.parent) # nested dict
else:
self.observer[self.name] = json.dumps(self) # the top-level dict
确保“父母”始终是self
,就像第一次初始化对象(即A
)时给出的那样。
答案 1 :(得分:0)
您可以使类更简单的一件事是外部化更新B
的行为,如下所示:
class ObservedDict(dict):
def __init__(self, initial_dict, on_changed=None):
super().__init__(initial_dict)
self.on_changed = on_changed
for k, v in initial_dict.items():
if isinstance(v, dict):
super().__setitem__(
k, ObservedDict(v, on_changed=self.notify))
self.notify()
def __setitem__(self, key, value):
if isinstance(value, dict):
value = ObservedDict(value, on_changed=self.notify)
super().__setitem__(key, value)
self.notify()
def notify(self, updated=None):
if self.on_changed is not None:
self.on_changed(self)
然后您可以将其与lambda一起使用:
import json
B = {}
A = ObservedDict(
{'foo': 1, 'bar': {'foobar': 2}},
lambda d: B.update({'observed': json.dumps(d)}))
print(B)
A['foo'] = 2
print(B)
A['bar'] = {'foobar': 4}
print(B)
A['bar']['foobar'] = 5
print(B)
或带有子类
class UpdateObserverDict(ObservedDict):
def __init__(self, *args, name, observer, **kwargs):
self.observer = observer
self.name = name
super().__init__(*args, **kwargs)
def notify(self, updated=None):
self.observer[self.name] = json.dumps(self)
B = {}
A = UpdateObserverDict(
{'foo': 1, 'bar': {'foobar': 2}},
name='observed', observer=B)
print(B)
A['foo'] = 2
print(B)
A['bar'] = {'foobar': 4}
print(B)
A['bar']['foobar'] = 5
print(B)
两者都能给您带来预期的结果:
{'observed': '{"foo": 1, "bar": {"foobar": 2}}'}
{'observed': '{"foo": 2, "bar": {"foobar": 2}}'}
{'observed': '{"foo": 2, "bar": {"foobar": 4}}'}
{'observed': '{"foo": 2, "bar": {"foobar": 5}}'}