overriding __getitem__ for a subclass of dict

Gary Herron gherron at islandtraining.com
Sun Nov 15 20:19:11 CET 2009


Steve Howell wrote:
> I ran the following program, and found its output surprising in one
> place:
>
>     class OnlyAl:
>         def __getitem__(self, key): return 'al'
>
>     class OnlyBob(dict):
>         def __getitem__(self, key): return 'bob'
>
>     import sys; print sys.version
>
>     al = OnlyAl()
>     bob = OnlyBob()
>
>     print al['whatever']
>     al.__getitem__ = lambda key: 'NEW AND IMPROVED AL!'
>     print al['whatever']
>
>     print bob['whatever']
>     bob.__getitem__ = lambda key: 'a NEW AND IMPROVED BOB seems
> impossible'
>     print bob['whatever']
>
>     2.6.2 (release26-maint, Apr 19 2009, 01:56:41)
>     [GCC 4.3.3]
>     al
>     NEW AND IMPROVED AL!
>     bob
>     bob
>   

It's the difference between old-style and new-style classes.  Type dict 
and therefore OnlyBob are new style.  OnlyAl defaults to old-style.  If 
you derive OnlyAl from type object, you'll get consistent results.

Gary Herron



> In attempting to change the behavior for bob's dictionary lookup, I am
> clearly doing something wrong, or maybe even impossible.
>
> Obviously the examples are contrived, but I am interested on a purely
> academic level why setting __getitem__  on bob does not seem to change
> the behavior of bob['foo'].   Note that OnlyBob subclasses dict;
> OnlyAl does not.
>
> On a more practical level, I will explain what I am trying to do.
> Basically, I am trying to create some code that allows me to spy on
> arbitrary objects in a test environment.  I want to write a spy()
> method that takes an arbitrary object and overrides its implementation
> of __getitem__ and friends so that I can see how library code is
> invoking the object (with print statements or whatever).  Furthermore,
> I want spy() to recursively spy on objects that get produced from my
> original object.  The particular use case is that I am creating a
> context for Django templates, and I want to see which objects are
> getting rendered, all the way down the tree.  It would be pretty easy
> to just create a subclass of the context method to spy at the top
> level, but I want to recursively spy on all its children, and that is
> why I need a monkeypatching approach.  The original version had spy
> recursively returning proxy/masquerade objects that intercepted
> __getitem__ calls, but it becomes brittle when the proxy objects go
> off into places like template filters, where I am not prepared to
> intercept all calls to the object, and where in some cases it is
> impossible to gain control.
>
> Although I am interested in comments on the general problems (spying
> on objects, or spying on Django template rendering), I am most
> interested in the specific mechanism for changing the __getitem__
> method for a subclass on a dictionary.  Thanks in advance!
>
>   




More information about the Python-list mailing list