我正在调试一些代码,我想知道何时访问特定的字典。好吧,它实际上是一个子类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
,并将调用更改为超级构造函数。但是,似乎没有任何事情发生。我以为我很聪明,但我想知道我是否应该走另一个方向。
感谢您的帮助!
答案 0 :(得分:65)
子类化dict
时的另一个问题是内置__init__
没有调用update
,而内置update
没有调用{{1} }}。因此,如果您希望所有setitem操作都通过__setitem__
函数,则应确保自己调用它:
__setitem__
答案 1 :(得分:31)
你所做的应该绝对有用。我测试了你的课程,除了日志语句中缺少左括号外,它的工作正常。我能想到的只有两件事。首先,是否正确设置了日志语句的输出?您可能需要在脚本的顶部放置logging.basicConfig(level=logging.DEBUG)
。
其次,__getitem__
和__setitem__
仅在[]
次访问期间调用。因此,请务必仅通过DictWatch
访问d[key]
,而不是d.get()
和d.set()
答案 2 :(得分:9)
这不应该真正改变结果(对于良好的记录阈值,这应该有效): 你的 init 应该是:
def __init__(self,*args,**kwargs) : dict.__init__(self,*args,**kwargs)
相反,因为如果用DictWatch([(1,2),(2,3)])或DictWatch(a = 1,b = 2)调用你的方法,这将失败。
(或者,更好的是,不要为此定义构造函数)
答案 3 :(得分:7)
考虑继承UserDict
或UserList
。这些类旨在进行子类化,而普通dict
和list
不是,并且包含优化。
答案 4 :(得分:1)
你所要做的只是
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中测试
答案 5 :(得分:0)
要完成安德鲁·帕特的答案,下面的示例显示了dict
和UserDict
之间的区别:
正确地覆盖字典是很困难的:
class MyDict(dict):
def __setitem__(self, key, value):
super().__setitem__(key, value * 10)
d = MyDict(a=1, b=2) # Bad! MyDict.__setitem__ not called
d.update(c=3) # Bad! MyDict.__setitem__ not called
d['d'] = 4 # Good!
print(d) # {'a': 1, 'b': 2, 'c': 3, 'd': 40}
UserDict
继承自collections.abc.MutableMapping
,因此更易于自定义:
class MyDict(collections.UserDict):
def __setitem__(self, key, value):
super().__setitem__(key, value * 10)
d = MyDict(a=1, b=2) # Good: MyDict.__setitem__ correctly called
d.update(c=3) # Good: MyDict.__setitem__ correctly called
d['d'] = 4 # Good
print(d) # {'a': 10, 'b': 20, 'c': 30, 'd': 40}
类似地,您只需实现__getitem__
即可自动与key in my_dict
,my_dict.get
,...
注意:UserDict
不是dict
的子类,因此isinstance(UserDict(), dict)
将失败(但isinstance(UserDict(), collections.abc.MutableMapping)
将起作用)