如何正确地子类化dict并重写__getitem__和__setitem__
我正在调试一些代码,想知道什么时候会访问一个特定的字典。其实,这个字典是一个类,它是从 dict
这个内置字典类派生出来的,并且增加了一些额外的功能。总之,我想自己也从 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
继承,而不是 dict
,并且修改了调用父类构造函数的部分。不过,现在似乎没有任何反应。我原以为我很聪明,但我在想是不是应该换个方向来做。
6 个回答
89
当你在创建一个新的字典类(也就是从dict
继承)时,有一个问题需要注意:内置的__init__
方法不会自动调用update
,而内置的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).items():
self[k] = v
45
你现在做的事情应该是完全可以的。我测试了你的类,除了你的日志语句里缺少一个开括号之外,其他都没问题。我能想到的只有两点。首先,你的日志语句输出设置正确了吗?你可能需要在脚本的开头加上 logging.basicConfig(level=logging.DEBUG)
。
其次,__getitem__
和 __setitem__
只有在使用 []
访问时才会被调用。所以确保你是通过 d[key]
来访问 DictWatch
,而不是用 d.get()
和 d.set()
。