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

2024-05-08 19:11:59 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在调试一些代码,我想知道何时访问特定的字典。实际上,它是一个类,它对dict进行子类化并实现一些额外的特性。无论如何,我想做的是我自己的子类dict,并添加override__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,而不是dict,并更改了对超级构造函数的调用。不过,似乎什么也没发生。我以为我很聪明,但我不知道我是否应该换个方向。

谢谢你的帮助!


Tags: keynameselfloginitdefargsval
3条回答

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

其次,__getitem____setitem__只在[]访问期间调用。因此,请确保只通过d[key]访问DictWatch,而不是d.get()d.set()

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

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

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

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

子类化dict时的另一个问题是内置的__init__不调用update,内置的update不调用__setitem__。因此,如果您希望所有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

相关问题 更多 >