overriding __getitem__ for a subclass of dict

Steve Howell showell30 at yahoo.com
Sun Nov 15 13:25:43 EST 2009


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

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