委托给 Python 中的字典 class
Delegate to a dict class in Python
在 Python 3 中,我有一个列表树和从另一个库获得的字典。我想用包含更多行为的对象来检测那棵树中的字典(为简单的字典 classes 提供更丰富的模型)。我试过用 dict 的子 class 替换这些对象的 class,但这是不允许的:
class MyClass(dict): pass
{}.__class__ = MyClass
失败 TypeError: __class__ assignment: only for heap types
。
所以我改为尝试编写包装器或适配器或委托 class:
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)
但是,doctests 在 inst['a']
处失败,TypeError: 'InstrumentedDict' object is not subscriptable
。但是请注意,它不会调用 __hasattr__
或 __getitem__
.
我希望将所有行为委托给底层字典,我希望不必考虑或显式委托字典的整个签名。
重要的是,class 所做的任何事情都应该影响底层字典(而不是创建对值的单独引用)。理想情况下,它不应强加或否定底层映射的可变性,而应反映其行为。
有没有简单优雅的解决方案,既满足指定接口又不需要显式签名镜像(如this implementation)?
编辑: 澄清一下,我想在不创建新副本的情况下覆盖现有词典的行为,这样如果修改了检测副本,那么原始词典也会被修改。
冒着完全忽略问题要点的风险...
是否有任何理由构建代理而不是仅仅子类化 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
在 Python 3 中,我有一个列表树和从另一个库获得的字典。我想用包含更多行为的对象来检测那棵树中的字典(为简单的字典 classes 提供更丰富的模型)。我试过用 dict 的子 class 替换这些对象的 class,但这是不允许的:
class MyClass(dict): pass
{}.__class__ = MyClass
失败 TypeError: __class__ assignment: only for heap types
。
所以我改为尝试编写包装器或适配器或委托 class:
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)
但是,doctests 在 inst['a']
处失败,TypeError: 'InstrumentedDict' object is not subscriptable
。但是请注意,它不会调用 __hasattr__
或 __getitem__
.
我希望将所有行为委托给底层字典,我希望不必考虑或显式委托字典的整个签名。
重要的是,class 所做的任何事情都应该影响底层字典(而不是创建对值的单独引用)。理想情况下,它不应强加或否定底层映射的可变性,而应反映其行为。
有没有简单优雅的解决方案,既满足指定接口又不需要显式签名镜像(如this implementation)?
编辑: 澄清一下,我想在不创建新副本的情况下覆盖现有词典的行为,这样如果修改了检测副本,那么原始词典也会被修改。
冒着完全忽略问题要点的风险...
是否有任何理由构建代理而不是仅仅子类化 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