代码之家  ›  专栏  ›  技术社区  ›  Mr. Frobenius

拦截对对象属性的getitem调用

  •  2
  • Mr. Frobenius  · 技术社区  · 8 年前

    问题: 我怎么拦截 __getitem__ 调用对象属性?

    说明:

    因此,场景如下。我有一个将类似dict的对象存储为属性的对象。每次 _获取项目__ 调用此属性的方法,我希望截获该调用,并根据键对获取的项进行一些特殊处理。我想要的是这样的:

    class Test:
    
        def __init__(self):
            self._d = {'a': 1, 'b': 2}
    
        @property
        def d(self, key):
            val = self._d[key]
            if key == 'a':
                val += 2
            return val
    t = Test()
    assert(t.d['a'] == 3) # Should not throw AssertionError
    

    问题是@property方法实际上没有访问 _获取项目__ 调用,所以我根本无法检查是否要执行特殊的后处理步骤。

    重要提示:我不能将可变映射子类化,重写 _获取项目__ 我的子类的方法来执行此特殊处理,并将子类的实例存储在 self._d . 在我的实际代码中 自我。 已经是可变映射的子类,此子类的其他客户端需要访问未修改的数据。

    谢谢你的帮助!

    3 回复  |  直到 8 年前
        1
  •  3
  •   ShadowRanger    8 年前

    Mapping d self._d

    from collections.abc import Mapping
    
    class DProxy(Mapping):
        __slots__ = ('proxymap',)
        def __init__(self, proxymap):
            self.proxymap = proxymap
        def __getitem__(self, key):
            val = self.proxymap[key]
            if key == 'a':
                val += 2
            return val
        def __iter__(self):
            return iter(self.proxymap)
        def __len__(self):
            return len(self.proxymap)
    

    class Test:
        def __init__(self):
            self._d = {'a': 1, 'b': 2}
    
        @property
        def d(self):
            return DProxy(self._d)
    

    Test test.d[somekey] test.d __getitem__ somekey locald = test.d locald MutableMapping

    DProxy __init__

        2
  •  0
  •   Silvio Mayolo    8 年前

    dict

    class DictProxy(dict):
        def __getitem__(self, item):
            val = super().__getitem__(item)
            if item == 'a':
                val += 2
            return val
    
    class Test:
    
        def __init__(self):
            self._d = {'a': 1, 'b': 2}
    
        @property
        def d(self):
            return DictProxy(self._d)
    
    t = Test()
    assert(t.d['a'] == 3) # Does not throw AssertionError anymore :)
    

        3
  •  0
  •   Bharel    8 年前

    from collections import UserDict
    
    class DictProxy(UserDict):
        def __init__(self, d):
            self.data = d
    
        def __getitem__(self, item):
            val = super().__getitem__(item)
            if item == 'a':
                val += 2
            return val