在Python 3中,我有一个列表和词典树,我从另一个库中获取。我想用包含更多行为的对象来检测该树中的dicts(为简单的dict类提供更丰富的模型)。我已经尝试用dict的子类替换这些对象的类,但这是不允许的:
class MyClass(dict): pass
{}.__class__ = MyClass
失败了TypeError: __class__ assignment: only for heap types
。
所以我试图编写一个包装器或适配器或委托类:
class InstrumentedDict(object):
"""
Instrument an existing dictionary with additional
functionality, but always reference and mutate
the original dictionary.
>>> orig = {'a': 1, 'b': 2}
>>> inst = InstrumentedDict(orig)
>>> hasattr(inst, '__getitem__')
True
>>> inst.__getitem__('a')
1
>>> inst['a']
1
>>> inst['c'] = 3
>>> orig['c']
3
>>> inst.keys() == orig.keys()
True
"""
def __init__(self, orig):
self._orig = orig
def __getattribute__(self, name):
orig = super(InstrumentedDict, self).__getattribute__('_orig')
return orig.__getattribute__(name)
但是,inst['a']
TypeError: 'InstrumentedDict' object is not subscriptable
的文档测试失败。但请注意,它无法调用__hasattr__
或__getitem__
。
我希望将所有行为委托给基础字典,并且我不想考虑或明确委托字典的整个签名。
重要的是,无论这个类做什么都应该影响底层的dict(而不是创建对值的单独引用)。理想情况下,它不应强加或否定底层Mapping的可变性,但应反映其行为。
是否有符合指定界面的简单而优雅的解决方案,但不需要对签名进行显式镜像(例如在this implementation中)?
编辑:为了澄清,我想在不创建新副本的情况下在现有字典上叠加行为,这样如果修改了经过检测的副本,那么原始副本也是如此。
答案 0 :(得分:3)
冒着完全忽略问题的风险......
有没有理由建立代理而不是仅仅为dict
创建子类?类似的东西:
class InstrumentedDict(dict):
""" Walks like a dict, talks like a dict... """
评论后修改:
啊,我明白了:)有道理......
似乎UserDict
就是答案,请查看:
from collections import UserDict
class InstrumentedDict(UserDict):
def __init__(self, data):
super(InstrumentedDict, self).__init__()
self.data = data
remote_dict = {"a": 1}
instr_dict = InstrumentedDict(remote_dict)
print(instr_dict) # {'a': 1}
instr_dict["b"] = 2
print(instr_dict) # {'a': 1, 'b': 2}
print(remote_dict) # {'a': 1, 'b': 2}
UserDict
似乎是我们不能直接将dict
子类化的古代遗物。但它很有用,因为它暴露了data
属性。而这几乎就是文档所说的所有内容:UserDict