代码之家  ›  专栏  ›  技术社区  ›  Michael Mior

如何正确地将dict子类化并重写getitem__

  •  67
  • Michael Mior  · 技术社区  · 15 年前

    我正在调试一些代码,我想知道何时访问特定的字典。实际上,它是一个 dict 实现了一些额外的特性。无论如何,我想做的是子类 小精灵 我自己和添加覆盖 __getitem__ __setitem__ 产生一些调试输出。现在,我有

    class DictWatch(dict):
        def __init__(self, *args):
            dict.__init__(self, args)
    
        def __getitem__(self, key):
            val = dict.__getitem__(self, key)
            log.info("GET %s['%s'] = %s" % str(dict.get(self, 'name_label')), str(key), str(val)))
            return val
    
        def __setitem__(self, key, val):
            log.info("SET %s['%s'] = %s" % str(dict.get(self, 'name_label')), str(key), str(val)))
            dict.__setitem__(self, key, val)
    

    name_label' 是一个最终将被设置的键,我想用它来标识输出。然后我将要检测的类更改为子类 DictWatch 而不是 小精灵 改变了对超级结构的调用。不过,似乎什么也没发生。我以为我很聪明,但我不知道我是否应该换个方向。

    谢谢你的帮助!

    5 回复  |  直到 7 年前
        1
  •  30
  •   adamJLev    13 年前

    你现在所做的绝对有效。我测试了您的类,除了日志语句中缺少左括号外,它工作得很好。我只能想到两件事。首先,日志语句的输出设置是否正确?你可能需要 logging.basicConfig(level=logging.DEBUG) 在你剧本的顶端。

    第二, __getitem__ __setitem__ 只在 [] 访问。所以请确保你只能访问 DictWatch 通过 d[key] ,而不是 d.get() d.set()

        2
  •  60
  •   Matt Anderson    15 年前

    子类化时的另一个问题 dict 是内置的吗 __init__ 不叫 update ,以及内置的 更新 不叫 __setitem__ . 所以,如果你想让所有的setitem操作通过 第七节 函数,您应该确保它被自己调用:

    class DictWatch(dict):
        def __init__(self, *args, **kwargs):
            self.update(*args, **kwargs)
    
        def __getitem__(self, key):
            val = dict.__getitem__(self, key)
            print 'GET', key
            return val
    
        def __setitem__(self, key, val):
            print 'SET', key, val
            dict.__setitem__(self, key, val)
    
        def __repr__(self):
            dictrepr = dict.__repr__(self)
            return '%s(%s)' % (type(self).__name__, dictrepr)
    
        def update(self, *args, **kwargs):
            print 'update', args, kwargs
            for k, v in dict(*args, **kwargs).iteritems():
                self[k] = v
    
        3
  •  9
  •   makapuf    15 年前

    这不应该真正改变结果(对于良好的日志阈值,这应该有效): 你的 初始化 应该是:

    def __init__(self,*args,**kwargs) : dict.__init__(self,*args,**kwargs) 
    

    相反,因为如果使用dictwatch([(1,2),(2,3)])或dictwatch(a=1,b=2)调用方法,这将失败。

    (或者,最好不要为此定义构造函数)

        4
  •  7
  •   Michael come lately PhiLho    7 年前

    考虑子类化 UserDict UserList . 这些类被设计为子类,而 dict list 不是,而且包含优化。

        5
  •  1
  •   ravi404 Reza    7 年前

    你要做的就是

    class BatchCollection(dict):
        def __init__(self, inpt={}):
            super(BatchCollection, self).__init__(inpt)
    

    供我个人使用的示例用法

    ### EXAMPLE
    class BatchCollection(dict):
        def __init__(self, inpt={}):
            super(BatchCollection, self).__init__(inpt)
    
        def __setitem__(self, key, item):
            if (isinstance(key, tuple) and len(key) == 2
                    and isinstance(item, collections.Iterable)):
                # self.__dict__[key] = item
                super(BatchCollection, self).__setitem__(key, item)
            else:
                raise Exception(
                    "Valid key should be a tuple (database_name, table_name) "
                    "and value should be iterable")
    

    注释 :仅在python3中测试