On Nov 16, 5:46 pm, Steven D'Aprano <ste...@remove.this.cybersource.com.au> wrote: > On Mon, 16 Nov 2009 10:32:19 -0800, Steve Howell wrote: > > Actually, the __getitem__ workaround that I proposed earlier only works > > on subclasses of dict, not dict themselves. So given a pure dictionary > > object, it is impossible to hook into attribute lookups after > > instantiation in debugging/tracing code. > > If you have written your application to avoid unnecessary isinstance and > type checks, i.e. to use duck-typing, then a technique you might find > useful is delegation. > > class DebuggingDict(object): > def __init__(self, dict_to_wrap, hook=None): > self.__dict__['_d'] = dict_to_wrap > self.__dict__['getitem_hook'] = hook > def __getattr__(self, name): > return getattr(self._d, name) > def __setattr__(self, name, value): > setattr(self._d, name, value) > def __getitem__(self, key): > if self.getitem_hook is not None: > self.getitem_hook(self, key) > return self._d[key] > > And in use: > > >>> def hook(self, key): > > ... print "Looking for key", key > ...>>> d = DebuggingDict({1:'a', 2: 'b'}, hook) > >>> d[1] > > Looking for key 1 > 'a'>>> d[2] > > Looking for key 2 > 'b' >
Yep, this basically resembles the approach that I originally took for the broader problem, which was that I wanted to see how a third party library (the Django templating system) was accessing dictionaries that referred to objects that my tracing code did not create. Although I did not instantiate the original objects, I did have the ability to substitute masquerade objects for the original objects before passing them along, and my code for the masquerading objects was similar in spirit to your DebuggingDict. It actually worked pretty well, except that eventually my masquerade objects went off to places where I was not fully able to maintain the illusion of being the original object. My original post on this thread sheds some light on what I'm doing, but basically I was trying to masquerade down the whole tree of calls from Django, which worked fine as long as Django was trying first to access my objects like dictionaries, which it always does first when rendering template variables, but all bets are off after that (custom filters, etc.). Eventually, I realized that it was easier to just monkeypatch Django while I was in test mode to get a more direct hook into the behavior I was trying to monitor, and then I didn't need to bother with overriding __getitem__ or creating complicated wrapper objects. I wrote about it here if anybody is morbidly interested: http://showellonprogramming.blogspot.com/ -- http://mail.python.org/mailman/listinfo/python-list