Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly subclass dict and override __getitem__ & __setitem__

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!

like image 399
Michael Mior Avatar asked Mar 06 '10 00:03

Michael Mior


People also ask

How do I override a dictionary in Python?

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.

How do you create a subclass in Python?

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.

What is the use of dict method?

The dict() method creates a dictionary object from the specified keys and values, or iterables of keys and values or mapping objects.


2 Answers

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 
like image 166
Matt Anderson Avatar answered Oct 20 '22 10:10

Matt Anderson


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()

like image 40
BrainCore Avatar answered Oct 20 '22 12:10

BrainCore