__getitem__ on new-style classes

Michael Spencer mahs at telcopartners.com
Thu Mar 10 22:40:24 EST 2005


simon at arrowtheory.com wrote:
> What i'm trying to do is tie special methods of a "proxy" instance
> to another instance:
...
> new style classes:
> 
> def test2():
>   print "test2"
>   class Container(object):
>     def __init__( self, data ):
>       self.data = data
> #      self.__dict__["__getitem__"] = self.data.__getitem__
>       self.__setattr__( "__getitem__", self.data.__getitem__ )
>   data = range(10)
>   c = Container(data)
>   print
>   print c.__getitem__(3) # works OK
>   print c[3] # fails


> 
> I get a "TypeError: unindexable object". It
> seems that c[] does not call __getitem__ in this case.
because __getitem__ is looked up in the class, not the instance dictionary
> 
> The plot thickens, however, when one tries the following:
> 
> def test3():
>   data = range(10)
>   c = type( "Container", (), { "__getitem__":data.__getitem__ } )()
>   print "test3"
>   print c[3]

Here you've created an entry in the class dictionary, just like writing
data = range(10)
class Container(object):
     __getitem__ = data.__getitem__

but, this probably doesn't help you much if you want the method to delegate to 
an attribute of the instance, since the instance is unavailable at class 
definition time

So, one solution, is to use create a delegating descriptor, like so:

class Delegate(object):
     def __init__(self, attrname):
         self.attrname = attrname
     def __get__(self, obj, cls):
         if isinstance(obj, cls):
             # Note that the attribute is looked up on obj._data
             return getattr(obj._data, self.attrname)
         else:
             return self

class Example(object):
     __getitem__ =  Delegate("__getitem__")

     def __init__(self, delegate):
         self._data = delegate

  >>> e = Example(range(10))
  >>> e[3]
  3


Michael





More information about the Python-list mailing list