简体   繁体   中英

Delegate to a dict class in Python

In Python 3, I have a tree of lists and dicts that I get from another library. I'd like to instrument the dicts in that tree with objects containing more behavior (giving a richer model to the simple dict classes). I've tried replacing the class of these objects with a subclass of dict, but that is not allowed:

class MyClass(dict): pass
{}.__class__ = MyClass

That fails with TypeError: __class__ assignment: only for heap types .

So I'm instead trying to write a wrapper or adapter or delegate 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)

However, the doctests fail at inst['a'] with TypeError: 'InstrumentedDict' object is not subscriptable . Note, however, that it doesn't fail to invoke __hasattr__ or __getitem__ .

I'm hoping to delegate all behavior to the underlying dictionary, and I'd like not to have to think about or explicitly delegate the whole signature of a dictionary.

It's important that whatever this class does should affect the underlying dict (rather than creating separate references to the values). Ideally, it should not impose or negate mutability on the underlying Mapping, but should mirror its behavior.

Is there a simple and elegant solution that meets the specified interface but doesn't require explicit mirroring of the signature (such as in this implementation )?

Edit: To clarify, I want to overlay behavior on existing dictionaries without creating new copies, such that if the instrumented copy is modified, so is the original.

At a risk of completely missing the point of your question...

Is there any reason to build a proxy instead of just subclassing dict ? Something like:

class InstrumentedDict(dict):
    """ Walks like a dict, talks like a dict... """

Edit after comment:

Ah, I see :) Makes sense...

Seems like UserDict is the answer, check this out:

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 seems to be a relic from olden days when we couldn't subclass dict directly. But it's useful because it exposes data attribute. And that's pretty much all what the docs say: UserDict

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM