overriding __getitem__ for a subclass of dict

Steve Howell showell30 at yahoo.com
Sun Nov 15 17:52:54 EST 2009


On Nov 15, 12:01 pm, Jon Clements <jon... at googlemail.com> wrote:
> On Nov 15, 7:23 pm, Steve Howell <showel... at yahoo.com> wrote:
>
> > On Nov 15, 10:25 am, Steve Howell <showel... at yahoo.com> wrote:
>
> > > [see original post...]
> > > I am most
> > > interested in the specific mechanism for changing the __getitem__
> > > method for a subclass on a dictionary.  Thanks in advance!
>
> > Sorry for replying to myself, but I just realized that the last
> > statement in my original post was a little imprecise.
>
> > I am more precisely looking for a way to change the behavior of foo
> > ['bar'] (side effects and possibly return value) where "foo" is an
> > instance of a class that subclasses "dict," and where "foo" is not
> > created by me.  The original post gives more context and example code
> > that does not work as I expect/desire.
>
> [quote fromhttp://docs.python.org/reference/datamodel.html]
> For instance, if a class defines a method named __getitem__(), and x
> is an instance of this class, then x[i] is roughly equivalent to
> x.__getitem__(i) for old-style classes and type(x).__getitem__(x, i)
> for new-style classes.
> [/quote]
>

Ok, thanks to Jon and Gary pointing me in the right direction, I think
I can provide an elaborate answer my own question now.

Given an already instantiated instance foo of Foo where Foo subclasses
dict, you cannot change the general behavior of calls of the form foo
[bar]. (Obviously you can change the behavior for specific examples of
bar after instantiation by setting foo['apple'] and foo['banana'] as
needed, but that's not what I mean.)

This may be surprising to naive programmers like myself, given that is
possible to change the behavior of foo.bar() after instantiation by
simply saying "foo.bar = some_method".  Also, with old-style classes,
you can change the behavior of foo[bar] by setting foo.__getitem__.
Even in new-style classes, you can change the behavior of
foo.__getitem__(bar) by saying foo.__getitem__ = some_method, but it
is a pointless exercise, since foo.__getitem__ will have no bearing on
the processing of "foo[bar]."  Finally, you can define __getitem__ on
the Foo class itself to change how foo[bar] gets resolved, presumably
even after instantiation of foo itself (but this does not allow for
instance-specific behavior).

Here is the difference:

  foo.value looks for a definition of value on the instance before
looking in the class hierarchy
  foo[bar] can find __getitem__ on foo before looking at Foo and its
superclasses, if Foo is old-style
  foo[bar] will only look for __getitem__ in the class hierarchy if
Foo derives from a new-style class

Does anybody have any links that points to the rationale for ignoring
instance definitions of __getitem__ when new-style classes are
involved?  I assume it has something to do with performance or
protecting us from our own mistakes?

So now I am still in search of a way to hook into calls to foo[bar]
after foo has been instantiated.  It is all test code, so I am not
particularly concerned about safety or future compatibility.  I can do
something really gross like monkeypatch Foo class instead of foo
instance and keep track of the ids to decide when to override
behavior, but there must be a simpler way to do this.



More information about the Python-list mailing list