overriding __getitem__ for a subclass of dict
Gary Herron
gherron at islandtraining.com
Sun Nov 15 14:19:11 EST 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