__getitem__ on new-style classes

S

simon

What i'm trying to do is tie special methods of a "proxy" instance
to another instance:

def test1():
class Container:
def __init__( self, data ):
self.data = data
self.__getitem__ = self.data.__getitem__

data = range(10)
c = Container(data)
print "test1"
print c[3]

This works OK. But when I try the same thing on
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.

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]

Which works fine. However, if I need to resort to
such trickery, no-one here where i work will have any idea
what it does :)

Would anyone like to shed some light on what is going on here ?

bye,

Simon.
 
M

Michael Spencer

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,997
Messages
2,570,239
Members
46,827
Latest member
DMUK_Beginner

Latest Threads

Top