I am debugging some code and I want to find out when a particular dictionary is accessed. Well, it's actually a class that subclass dict
and implements a couple extra features. Anyway, what I would like to do is subclass dict
myself and add override __getitem__
and __setitem__
to produce some debugging output. Right now, I have
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'
is a key which will eventually be set that I want to use to identify the output. I have then changed the class I am instrumenting to subclass DictWatch
instead of dict
and changed the call to the superconstructor. Still, nothing seems to be happening. I thought I was being clever, but I wonder if I should be going a different direction.
Thanks for the help!
To override a dict with Python, we can create a subclass of the MutableMapping class. to create a TransformedDict class that is a subclass of the MutableMapping . We use a dict as the value of the store instance variable.
The process of creating a subclass of a class is called inheritance. All the attributes and methods of superclass are inherited by its subclass also. This means that an object of a subclass can access all the attributes and methods of the superclass.
The dict() method creates a dictionary object from the specified keys and values, or iterables of keys and values or mapping objects.
Another issue when subclassing dict
is that the built-in __init__
doesn't call update
, and the built-in update
doesn't call __setitem__
. So, if you want all setitem operations to go through your __setitem__
function, you should make sure that it gets called yourself:
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
What you're doing should absolutely work. I tested out your class, and aside from a missing opening parenthesis in your log statements, it works just fine. There are only two things I can think of. First, is the output of your log statement set correctly? You might need to put a logging.basicConfig(level=logging.DEBUG)
at the top of your script.
Second, __getitem__
and __setitem__
are only called during []
accesses. So make sure you only access DictWatch
via d[key]
, rather than d.get()
and d.set()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With